From 9c264e0f1fb94df97f734cbc45269cd477e4cf4f Mon Sep 17 00:00:00 2001 From: Shen-Ta Hsieh Date: Tue, 3 Nov 2026 00:12:43 +0800 Subject: [PATCH] Fix the MSVC warning and the no-exceptions link error in mode_has_nan - MSVC gave C4702 (unreachable code) for the return after boost::throw_exception, which stopped builds that treat warnings as errors. Keep the result of the NaN search in a variable, and return it after the throw, so that no statement follows the throw. - Without exceptions, Boost requires the program to define boost::throw_exception, so programs that call mode did not link. Throw only if BOOST_MATH_NO_EXCEPTIONS is not set, as the policies do, which select errno_on_error by default. - Without exceptions, the function returns true for data that contain a NaN, and mode gives no result. Document this. - Add a test that runs with and without exceptions, and add it to no_eh_tests. Fixes #1621 --- doc/statistics/univariate_statistics.qbk | 1 + .../math/statistics/detail/single_pass.hpp | 8 +++-- test/Jamfile.v2 | 2 ++ test/git_issue_1621.cpp | 29 +++++++++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 test/git_issue_1621.cpp diff --git a/doc/statistics/univariate_statistics.qbk b/doc/statistics/univariate_statistics.qbk index bcef9dd9ed..bb8c59d2cc 100644 --- a/doc/statistics/univariate_statistics.qbk +++ b/doc/statistics/univariate_statistics.qbk @@ -392,6 +392,7 @@ Compute the mode(s) of a data set: /Nota bene/: The input data must be sorted in order to pass a forward iterator. If data is not sorted random access iterators are required for a call to `std::sort`. Data containing a NaN have no mode, and a `std::domain_error` is thrown. +If exceptions are disabled, no mode is written. [heading References] diff --git a/include/boost/math/statistics/detail/single_pass.hpp b/include/boost/math/statistics/detail/single_pass.hpp index d428db0f26..ed7690f5fb 100644 --- a/include/boost/math/statistics/detail/single_pass.hpp +++ b/include/boost/math/statistics/detail/single_pass.hpp @@ -369,12 +369,14 @@ template bool mode_has_nan(ForwardIterator first, ForwardIterator last) { using Z = typename std::iterator_traits::value_type; - if (std::any_of(first, last, [](const Z& z) { return !(z == z); })) + const bool has_nan = std::any_of(first, last, [](const Z& z) { return !(z == z); }); +#ifndef BOOST_MATH_NO_EXCEPTIONS + if (has_nan) { BOOST_MATH_THROW_EXCEPTION(std::domain_error("The mode is undefined for data containing a NaN.")) - return true; } - return false; +#endif + return has_nan; } template diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c6fedef6c5..74a583d5f6 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1117,6 +1117,7 @@ test-suite misc : /boost/test//boost_unit_test_framework ] [ run test_ulp.cpp /boost/test//boost_unit_test_framework ] [ run git_issue_1419.cpp ] + [ run git_issue_1621.cpp ] [ compile-fail git_issue_1421.cpp ] # [ run __temporary_test.cpp test_instances//test_instances : : : always_show_run_output off ] @@ -2004,6 +2005,7 @@ alias no_eh_tests : #test_tools_ulps_plot_incl #test_tools_ulps_heatmap_incl test_tools_workaround_incl + git_issue_1621 ; explicit no_eh_tests ; diff --git a/test/git_issue_1621.cpp b/test/git_issue_1621.cpp new file mode 100644 index 0000000000..8f24bf7a1d --- /dev/null +++ b/test/git_issue_1621.cpp @@ -0,0 +1,29 @@ +// Copyright 2026 Shen-Ta Hsieh +// Use, modification and distribution are subject to 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) +// +// See: https://github.com/boostorg/math/issues/1621 + +#include +#include +#include +#include +#include +#include + +int main() +{ + std::vector v {1.0, 2.0, 2.0, std::numeric_limits::quiet_NaN()}; + std::vector modes; + + // Without exceptions, data that contain a NaN give no mode, and boost::throw_exception is not called +#ifndef BOOST_MATH_NO_EXCEPTIONS + BOOST_TEST_THROWS(boost::math::statistics::mode(v.begin(), v.end(), std::back_inserter(modes)), std::domain_error); +#else + boost::math::statistics::mode(v.begin(), v.end(), std::back_inserter(modes)); +#endif + BOOST_TEST(modes.empty()); + + return boost::report_errors(); +}