From bb4ce528f3ff0642b59228fb6ac8642e443dbb6f Mon Sep 17 00:00:00 2001 From: Jean-Louis Leroy Date: Sat, 28 Feb 2026 10:17:53 -0500 Subject: [PATCH 1/3] better error message when overrider cannot be matched to method --- include/boost/openmethod/macros.hpp | 17 ++++++++++++++--- test/CMakeLists.txt | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/boost/openmethod/macros.hpp b/include/boost/openmethod/macros.hpp index 36980716..3a574ca9 100644 --- a/include/boost/openmethod/macros.hpp +++ b/include/boost/openmethod/macros.hpp @@ -37,6 +37,9 @@ struct va_args { using registry = macro_default_registry; }; +template +inline constexpr bool method_not_found = false; + } // namespace boost::openmethod::detail #define BOOST_OPENMETHOD_GENSYM BOOST_PP_CAT(openmethod_gensym_, __COUNTER__) @@ -82,10 +85,18 @@ struct va_args { struct BOOST_OPENMETHOD_OVERRIDERS(NAME) #define BOOST_OPENMETHOD_DETAIL_LOCATE_METHOD(NAME, ARGS) \ - template \ - struct boost_openmethod_detail_locate_method_aux; \ + template \ + struct boost_openmethod_detail_locate_method_aux { \ + static_assert( \ + ::boost::openmethod::detail::method_not_found, \ + "BOOST_OPENMETHOD_OVERRIDE: cannot find '" #NAME \ + "' method that accepts the same arguments as the overrider"); \ + }; \ template \ - struct boost_openmethod_detail_locate_method_aux { \ + struct boost_openmethod_detail_locate_method_aux< \ + void(A...), \ + std::void_t()...))>> { \ using type = \ decltype(BOOST_OPENMETHOD_GUIDE(NAME)(std::declval()...)); \ } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 88f4546f..06c2573e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -102,3 +102,5 @@ openmethod_compile_fail_test( compile_fail_virtual_parameter_private_base_core "must be an unambiguous accessible base") openmethod_compile_fail_test( compile_fail_repeated_inheritance "repeated inheritance") +openmethod_compile_fail_test( + compile_fail_override_method_not_found "cannot find 'speak' method that accepts the same arguments as the overrider") From 33c65691bbedd980779d50162558dafe79c97cde Mon Sep 17 00:00:00 2001 From: Jean-Louis Leroy Date: Sat, 28 Feb 2026 10:18:34 -0500 Subject: [PATCH 2/3] dlopen: make sure lib is built before running test --- .../ROOT/examples/shared_libs/CMakeLists.txt | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/doc/modules/ROOT/examples/shared_libs/CMakeLists.txt b/doc/modules/ROOT/examples/shared_libs/CMakeLists.txt index e73bd487..64aaabf5 100644 --- a/doc/modules/ROOT/examples/shared_libs/CMakeLists.txt +++ b/doc/modules/ROOT/examples/shared_libs/CMakeLists.txt @@ -7,6 +7,19 @@ message(STATUS "Boost.OpenMethod: building shared library examples") add_compile_definitions(BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS) +# All targets output to the same directory so that executables can locate shared +# libraries via boost::dll::program_location().parent_path(). +set(shared_libs_output_dir "${CMAKE_CURRENT_BINARY_DIR}") + +# Helper: add a CTest fixture that builds a CMake target, so that `ctest` alone +# (without a prior `cmake --build`) still works. +function(openmethod_shared_libs_build_fixture target) + add_test(NAME ${target}-build + COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" + --target ${target} --config $) + set_tests_properties(${target}-build PROPERTIES FIXTURES_SETUP ${target}-fixture) +endfunction() + # ------------------------------------------------------------------------------ # static linking @@ -15,21 +28,38 @@ target_link_libraries(boost_openmethod-shared Boost::openmethod) set_target_properties(boost_openmethod-shared PROPERTIES ENABLE_EXPORTS ON OUTPUT_NAME shared + LIBRARY_OUTPUT_DIRECTORY "${shared_libs_output_dir}" + RUNTIME_OUTPUT_DIRECTORY "${shared_libs_output_dir}" ) add_executable(boost_openmethod-static static_main.cpp) target_link_libraries(boost_openmethod-static Boost::openmethod Boost::dll boost_openmethod-shared) -add_test(NAME boost_openmethod-static COMMAND boost_openmethod-static) +set_target_properties(boost_openmethod-static PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${shared_libs_output_dir}" +) +openmethod_shared_libs_build_fixture(boost_openmethod-static) +add_test(NAME boost_openmethod-static + COMMAND "${shared_libs_output_dir}/boost_openmethod-static") +set_tests_properties(boost_openmethod-static PROPERTIES + FIXTURES_REQUIRED boost_openmethod-static-fixture) # ------------------------------------------------------------------------------ # dynamic loading, direct virtual_ptrs add_executable(boost_openmethod-dynamic dynamic_main.cpp) -set_target_properties(boost_openmethod-dynamic PROPERTIES ENABLE_EXPORTS ON) +set_target_properties(boost_openmethod-dynamic PROPERTIES + ENABLE_EXPORTS ON + RUNTIME_OUTPUT_DIRECTORY "${shared_libs_output_dir}" +) target_link_libraries(boost_openmethod-dynamic Boost::openmethod Boost::dll) add_dependencies(boost_openmethod-dynamic boost_openmethod-shared) if (NOT WIN32) - add_test(NAME boost_openmethod-dynamic COMMAND boost_openmethod-dynamic) + openmethod_shared_libs_build_fixture(boost_openmethod-shared) + openmethod_shared_libs_build_fixture(boost_openmethod-dynamic) + add_test(NAME boost_openmethod-dynamic + COMMAND "${shared_libs_output_dir}/boost_openmethod-dynamic") + set_tests_properties(boost_openmethod-dynamic PROPERTIES + FIXTURES_REQUIRED "boost_openmethod-shared-fixture;boost_openmethod-dynamic-fixture") endif() # ------------------------------------------------------------------------------ @@ -42,14 +72,23 @@ target_link_libraries(boost_openmethod-indirect_shared PRIVATE Boost::openmethod set_target_properties(boost_openmethod-indirect_shared PROPERTIES ENABLE_EXPORTS ON OUTPUT_NAME indirect_shared + LIBRARY_OUTPUT_DIRECTORY "${shared_libs_output_dir}" + RUNTIME_OUTPUT_DIRECTORY "${shared_libs_output_dir}" ) add_executable(boost_openmethod-indirect indirect_main.cpp) target_compile_definitions( boost_openmethod-indirect PUBLIC BOOST_OPENMETHOD_DEFAULT_REGISTRY=indirect_registry) -set_target_properties(boost_openmethod-indirect PROPERTIES ENABLE_EXPORTS ON) +set_target_properties(boost_openmethod-indirect PROPERTIES + ENABLE_EXPORTS ON + RUNTIME_OUTPUT_DIRECTORY "${shared_libs_output_dir}" +) target_link_libraries(boost_openmethod-indirect PRIVATE Boost::openmethod Boost::dll) add_dependencies(boost_openmethod-indirect boost_openmethod-indirect_shared) if (NOT WIN32) - add_test(NAME boost_openmethod-indirect COMMAND boost_openmethod-indirect) + openmethod_shared_libs_build_fixture(boost_openmethod-indirect) + add_test(NAME boost_openmethod-indirect + COMMAND "${shared_libs_output_dir}/boost_openmethod-indirect") + set_tests_properties(boost_openmethod-indirect PROPERTIES + FIXTURES_REQUIRED boost_openmethod-indirect-fixture) endif() From 599574559132275d6410c2ad28ce6395b433d5b4 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leroy Date: Sat, 28 Feb 2026 11:06:45 -0500 Subject: [PATCH 3/3] better error message when overrider cannot be matched to method --- ...compile_fail_override_method_not_found.cpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test/compile_fail_override_method_not_found.cpp diff --git a/test/compile_fail_override_method_not_found.cpp b/test/compile_fail_override_method_not_found.cpp new file mode 100644 index 00000000..160cd3a2 --- /dev/null +++ b/test/compile_fail_override_method_not_found.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2018-2025 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +using boost::openmethod::virtual_; + +struct Animal {}; +struct Dog : Animal {}; + +// Deliberately omit BOOST_OPENMETHOD(speak, ...) to trigger the static_assert. + +BOOST_OPENMETHOD_CLASSES(Animal, Dog); + +BOOST_OPENMETHOD_OVERRIDE(speak, (virtual_), void) { +} + +int main() { + return 0; +}