From 93231c6c2f3dac049b36126890632e8f27f24a1c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 30 Sep 2026 18:12:58 +0200 Subject: [PATCH] Factor the repeated JSON_HAS_RANGES/MinGW guard into one macro The std::ranges view conversion (excluded on MinGW because of its incomplete C++20 ranges support, #4916) was gated by the same #if JSON_HAS_RANGES && !defined(__MINGW32__) condition at seven independent sites in to_json.hpp and type_traits.hpp, with the MinGW rationale duplicated in two of them and missing from the rest. Since the sites come in matching pairs (one enables is_compatible_range_view and a view-based overload, the other adds the exclusion to the plain-array-type overload), a drift between any pair would produce an ambiguous or missing overload on exactly one platform. Add JSON_HAS_RANGE_VIEW_CONVERSION next to JSON_HAS_RANGES in macro_scope.hpp, combining both conditions with the #4916 reasoning in one place, #undef it in macro_unscope.hpp, and use it at all seven sites. This does not fold the MinGW check into JSON_HAS_RANGES itself: JSON_HAS_RANGES is user-overridable and also gates the enable_borrowed_range specialization in iteration_proxy.hpp, which is not excluded on MinGW. No behavior or public API change: JSON_HAS_RANGE_VIEW_CONVERSION expands to exactly the condition that was previously written out at each site. Overlaps #5585, #5600 and #3575, which touch the same to_json.hpp and type_traits.hpp lines; the change here is a mechanical search-and-replace of the guard condition and should rebase cleanly. Signed-off-by: Niels Lohmann #5708 item 11 --- .../nlohmann/detail/conversions/to_json.hpp | 10 +++--- include/nlohmann/detail/macro_scope.hpp | 12 +++++++ include/nlohmann/detail/macro_unscope.hpp | 1 + include/nlohmann/detail/meta/type_traits.hpp | 8 ++--- single_include/nlohmann/json.hpp | 31 ++++++++++++------- 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 491bb9873..7d9977d9e 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -178,7 +178,7 @@ struct external_constructor template < typename BasicJsonType, typename CompatibleArrayType, enable_if_t < !std::is_same::value -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION && !is_compatible_range_view::value #endif , int > = 0 > @@ -222,9 +222,7 @@ struct external_constructor j.assert_invariant(); } - // std::ranges does not work properly on MinGW due to incomplete C++20 support - // see https://github.com/nlohmann/json/issues/4916 -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION template>::value, int> = 0> static void construct(BasicJsonType& j, CompatibleArrayType && arr) @@ -379,7 +377,7 @@ template < typename BasicJsonType, typename CompatibleArrayType, !std::is_same::value&& !is_compatible_binary_type::value&& !is_basic_json::value -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION && !is_compatible_range_view::value #endif , @@ -389,7 +387,7 @@ inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) external_constructor::construct(j, arr); } -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION template < typename BasicJsonType, typename T, enable_if_t < is_compatible_range_view>::value && !is_compatible_string_type>::value diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 99512fa82..dce789f1c 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -159,6 +159,18 @@ #endif #endif +// std::ranges view conversion (to_json/is_compatible_array_type_impl) additionally +// needs to be disabled on MinGW, whose std::ranges support is incomplete +// (issue #4916); this macro combines both conditions so the check and its +// reason are not duplicated at every use site. +#ifndef JSON_HAS_RANGE_VIEW_CONVERSION + #if JSON_HAS_RANGES && !defined(__MINGW32__) + #define JSON_HAS_RANGE_VIEW_CONVERSION 1 + #else + #define JSON_HAS_RANGE_VIEW_CONVERSION 0 + #endif +#endif + #ifndef JSON_HAS_STD_FORMAT #if defined(JSON_HAS_CPP_20) && defined(__cpp_lib_format) #define JSON_HAS_STD_FORMAT 1 diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index a73951a22..b6f5c4804 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -40,6 +40,7 @@ #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef JSON_HAS_THREE_WAY_COMPARISON #undef JSON_HAS_RANGES + #undef JSON_HAS_RANGE_VIEW_CONVERSION #undef JSON_HAS_STD_FORMAT #undef JSON_HAS_STATIC_RTTI #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 497a98307..c9e578363 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -484,9 +484,7 @@ template struct is_range_view_optional_type> : std: template struct is_range_view_optional_type : std::false_type {}; #endif -// std::ranges does not work properly on MinGW due to incomplete C++20 support -// see https://github.com/nlohmann/json/issues/4916 -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION // SafeToCheck guards against types that trigger circular constraints when // std::ranges::view is evaluated on GCC 12 / libstdc++ 12: @@ -525,7 +523,7 @@ struct is_compatible_array_type_impl < // filter_view) can match BOTH this iterator-based specialization AND the view-based one // below, causing ambiguity. Exclude views here so the two specializations are mutually // exclusive: this one handles plain iterable containers, the other handles views. -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION && !is_compatible_range_view::value #endif >> @@ -535,7 +533,7 @@ struct is_compatible_array_type_impl < range_value_t>::value; }; -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION template struct is_compatible_array_type_impl < BasicJsonType, CompatibleArrayType, diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 73c70c5e9..146e46841 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2473,6 +2473,18 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif #endif +// std::ranges view conversion (to_json/is_compatible_array_type_impl) additionally +// needs to be disabled on MinGW, whose std::ranges support is incomplete +// (issue #4916); this macro combines both conditions so the check and its +// reason are not duplicated at every use site. +#ifndef JSON_HAS_RANGE_VIEW_CONVERSION + #if JSON_HAS_RANGES && !defined(__MINGW32__) + #define JSON_HAS_RANGE_VIEW_CONVERSION 1 + #else + #define JSON_HAS_RANGE_VIEW_CONVERSION 0 + #endif +#endif + #ifndef JSON_HAS_STD_FORMAT #if defined(JSON_HAS_CPP_20) && defined(__cpp_lib_format) #define JSON_HAS_STD_FORMAT 1 @@ -4451,9 +4463,7 @@ template struct is_range_view_optional_type> : std: template struct is_range_view_optional_type : std::false_type {}; #endif -// std::ranges does not work properly on MinGW due to incomplete C++20 support -// see https://github.com/nlohmann/json/issues/4916 -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION // SafeToCheck guards against types that trigger circular constraints when // std::ranges::view is evaluated on GCC 12 / libstdc++ 12: @@ -4492,7 +4502,7 @@ struct is_compatible_array_type_impl < // filter_view) can match BOTH this iterator-based specialization AND the view-based one // below, causing ambiguity. Exclude views here so the two specializations are mutually // exclusive: this one handles plain iterable containers, the other handles views. -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION && !is_compatible_range_view::value #endif >> @@ -4502,7 +4512,7 @@ struct is_compatible_array_type_impl < range_value_t>::value; }; -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION template struct is_compatible_array_type_impl < BasicJsonType, CompatibleArrayType, @@ -6584,7 +6594,7 @@ struct external_constructor template < typename BasicJsonType, typename CompatibleArrayType, enable_if_t < !std::is_same::value -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION && !is_compatible_range_view::value #endif , int > = 0 > @@ -6628,9 +6638,7 @@ struct external_constructor j.assert_invariant(); } - // std::ranges does not work properly on MinGW due to incomplete C++20 support - // see https://github.com/nlohmann/json/issues/4916 -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION template>::value, int> = 0> static void construct(BasicJsonType& j, CompatibleArrayType && arr) @@ -6785,7 +6793,7 @@ template < typename BasicJsonType, typename CompatibleArrayType, !std::is_same::value&& !is_compatible_binary_type::value&& !is_basic_json::value -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION && !is_compatible_range_view::value #endif , @@ -6795,7 +6803,7 @@ inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) external_constructor::construct(j, arr); } -#if JSON_HAS_RANGES && !defined(__MINGW32__) +#if JSON_HAS_RANGE_VIEW_CONVERSION template < typename BasicJsonType, typename T, enable_if_t < is_compatible_range_view>::value && !is_compatible_string_type>::value @@ -32530,6 +32538,7 @@ struct formatter // NOLINT(cert-dcl58-c #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef JSON_HAS_THREE_WAY_COMPARISON #undef JSON_HAS_RANGES + #undef JSON_HAS_RANGE_VIEW_CONVERSION #undef JSON_HAS_STD_FORMAT #undef JSON_HAS_STATIC_RTTI #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON