diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index d8c27c621..d8f15e3dd 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -100,7 +100,7 @@ jobs: container: ubuntu:focal strategy: matrix: - target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local] + target: [ci_cmake_flags, ci_test_diagnostics, ci_test_diagnostic_positions, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison, ci_test_noglobaludls, ci_test_disableenumserialization, ci_test_disabletuplereferenceconversion, ci_test_skiplibraryversioncheck, ci_test_simdutf, ci_test_strict_nul_handling, ci_test_no_thread_local] steps: - name: Install build-essential run: apt-get update ; apt-get install -y build-essential unzip wget git libssl-dev diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c43c23ff..f0a6771dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ option(JSON_Diagnostic_Positions "Enable diagnostic positions." OFF) option(JSON_GlobalUDLs "Place user-defined string literals in the global namespace." ON) option(JSON_ImplicitConversions "Enable implicit conversions." ON) option(JSON_DisableEnumSerialization "Disable default integer enum serialization." OFF) +option(JSON_DisableTupleReferenceConversion "Disable conversion from a one-element tuple of a JSON reference." OFF) option(JSON_LegacyDiscardedValueComparison "Enable legacy discarded value comparison." OFF) option(JSON_Install "Install CMake targets during install step." ${MAIN_PROJECT}) option(JSON_MultipleHeaders "Use non-amalgamated version of the library." ON) @@ -101,6 +102,10 @@ if (JSON_DisableEnumSerialization) message(STATUS "Enum integer serialization is disabled (JSON_DISABLE_ENUM_SERIALIZATION=1)") endif() +if (JSON_DisableTupleReferenceConversion) + message(STATUS "Tuple reference conversion is disabled (JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1)") +endif() + if (JSON_LegacyDiscardedValueComparison) message(STATUS "Legacy discarded value comparison enabled (JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1)") endif() @@ -143,6 +148,7 @@ target_compile_definitions( $<$>:JSON_USE_GLOBAL_UDLS=0> $<$>:JSON_USE_IMPLICIT_CONVERSIONS=0> $<$:JSON_DISABLE_ENUM_SERIALIZATION=1> + $<$:JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1> $<$:JSON_DIAGNOSTICS=1> $<$:JSON_DIAGNOSTIC_POSITIONS=1> $<$:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1> diff --git a/cmake/ci.cmake b/cmake/ci.cmake index 573a8e0e0..bfdec7ff9 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -276,6 +276,20 @@ add_custom_target(ci_test_disableenumserialization COMMENT "Compile and test with enum serialization disabled" ) +############################################################################### +# Disable conversion from a one-element tuple of a JSON reference. +############################################################################### + +add_custom_target(ci_test_disabletuplereferenceconversion + COMMAND ${CMAKE_COMMAND} + -DCMAKE_BUILD_TYPE=Debug -GNinja + -DJSON_BuildTests=ON -DJSON_FastTests=ON -DJSON_DisableTupleReferenceConversion=ON + -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion + COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion + COMMAND cd ${PROJECT_BINARY_DIR}/build_disabletuplereferenceconversion && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure + COMMENT "Compile and test with tuple reference conversion disabled" +) + ############################################################################### # Skip the multiple-inclusion library version check. ############################################################################### diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql index 38b203d38..f1f8de705 100644 --- a/docs/docset/docSet.sql +++ b/docs/docset/docSet.sql @@ -207,6 +207,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'a INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_ENUM_SERIALIZATION', 'Macro', 'api/macros/json_disable_enum_serialization/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DISABLE_TUPLE_REFERENCE_CONVERSION', 'Macro', 'api/macros/json_disable_tuple_reference_conversion/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_11', 'Macro', 'api/macros/json_has_cpp_11/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_14', 'Macro', 'api/macros/json_has_cpp_11/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_17', 'Macro', 'api/macros/json_has_cpp_11/index.html'); diff --git a/docs/mkdocs/docs/api/basic_json/basic_json.md b/docs/mkdocs/docs/api/basic_json/basic_json.md index 6aaab23c9..0954a27a1 100644 --- a/docs/mkdocs/docs/api/basic_json/basic_json.md +++ b/docs/mkdocs/docs/api/basic_json/basic_json.md @@ -159,6 +159,8 @@ basic_json(basic_json&& other) noexcept; - `CompatibleType` is not `basic_json` (to avoid hijacking copy/move constructors), - `CompatibleType` is not a different `basic_json` type (i.e. with different template arguments) - `CompatibleType` is not a `basic_json` nested type (e.g., `json_pointer`, `iterator`, etc.) + - if [`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../macros/json_disable_tuple_reference_conversion.md) is defined + to `1`: `CompatibleType` is not a one-element `std::tuple` holding a reference to `basic_json` - `json_serializer` (with `U = uncvref_t`) has a `to_json(basic_json_t&, CompatibleType&&)` method diff --git a/docs/mkdocs/docs/api/macros/index.md b/docs/mkdocs/docs/api/macros/index.md index bf773b5c4..c36eef88c 100644 --- a/docs/mkdocs/docs/api/macros/index.md +++ b/docs/mkdocs/docs/api/macros/index.md @@ -52,6 +52,7 @@ header. See also the [macro overview page](../../features/macros.md). - [**JSON_BRACE_INIT_COPY_SEMANTICS**](json_brace_init_copy_semantics.md) - opt in to copy/move semantics for single-element brace initialization - [**JSON_DISABLE_ENUM_SERIALIZATION**](json_disable_enum_serialization.md) - switch off default serialization/deserialization functions for enums +- [**JSON_DISABLE_TUPLE_REFERENCE_CONVERSION**](json_disable_tuple_reference_conversion.md) - switch off conversion from a one-element tuple of a JSON reference - [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions ## Comparison behavior diff --git a/docs/mkdocs/docs/api/macros/json_disable_tuple_reference_conversion.md b/docs/mkdocs/docs/api/macros/json_disable_tuple_reference_conversion.md new file mode 100644 index 000000000..c759fd65c --- /dev/null +++ b/docs/mkdocs/docs/api/macros/json_disable_tuple_reference_conversion.md @@ -0,0 +1,114 @@ +# JSON_DISABLE_TUPLE_REFERENCE_CONVERSION + +```cpp +#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION /* value */ +``` + +When defined to `1`, a `basic_json` value can no longer be constructed from a one-element `std::tuple` whose element is +a reference to that `basic_json` type, such as `std::tuple`, `std::tuple`, or `std::tuple`. +These are the tuples created by `std::forward_as_tuple(j)`. + +## Default definition + +The default value is `0` (disabled — existing behavior is preserved). + +```cpp +#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0 +``` + +## Notes + +!!! note "Background" + + By default, `basic_json` can be constructed from any `std::tuple` whose elements can be converted to JSON; the result + is an array. This includes `std::tuple`, which becomes a one-element array. + + `std::tuple` only converts another tuple element by element if its element type cannot be constructed from the whole + source tuple. Because `json` *can* be constructed from `std::tuple`, `std::tuple` instead converts the whole + tuple into a single `json` value. This has two surprising effects: + + ```cpp + json j = true; + + // rejected by some standard libraries (e.g., libc++); with others, the + // reference binds to a temporary that is destroyed right away + std::tuple t1(std::forward_as_tuple(j)); + + // compiles, but std::get<0>(t2) is [true], not true + std::tuple t2(std::forward_as_tuple(j)); + ``` + + Enabling this macro removes the conversion, so both tuples are converted element by element: `std::get<0>(t1)` + refers to `j`, and `std::get<0>(t2)` is a copy of `j` (see [#2226](https://github.com/nlohmann/json/issues/2226)). + +!!! warning "Opt-in only" + + This macro must be defined **before** including ``. Defining it after the include has no effect. + +!!! note "Affected conversions" + + Only one-element tuples holding a reference to the **same** `basic_json` type are affected. Constructing a JSON value + from them no longer compiles: + + ```cpp + json j = true; + json a = std::forward_as_tuple(j); // error with the macro enabled + json b = json::array({j}); // use this instead: [true] + ``` + + Tuples holding a JSON value (`std::make_tuple(j)`), tuples with more than one element, and tuples holding references + to other types (including other `basic_json` specializations) are converted to arrays as before. + +!!! hint "CMake option" + + This behavior can also be controlled with the CMake option + [`JSON_DisableTupleReferenceConversion`](../../integration/cmake.md#json_disabletuplereferenceconversion) + (`OFF` by default) which defines `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION` accordingly. + +## Examples + +??? example "Default behavior (macro not defined)" + + ```cpp + #include + + using json = nlohmann::json; + + int main() + { + json j = true; + + std::tuple t(std::forward_as_tuple(j)); + // std::get<0>(t) is [true] -- the whole tuple was converted + } + ``` + +??? example "Conversion disabled (macro defined to 1)" + + ```cpp + #define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 1 + #include + + using json = nlohmann::json; + + int main() + { + json j = true; + + std::tuple t(std::forward_as_tuple(j)); + // std::get<0>(t) is true -- a copy of j + + std::tuple r(std::forward_as_tuple(j)); + // std::get<0>(r) refers to j + } + ``` + +## See also + +- [**basic_json(CompatibleType&&)**](../basic_json/basic_json.md) - the affected constructor +- [:simple-cmake: JSON_DisableTupleReferenceConversion](../../integration/cmake.md#json_disabletuplereferenceconversion) - + CMake option to control the macro + +## Version history + +- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/features/macros.md b/docs/mkdocs/docs/features/macros.md index 2bc8a4a5b..bbeae1f3a 100644 --- a/docs/mkdocs/docs/features/macros.md +++ b/docs/mkdocs/docs/features/macros.md @@ -83,6 +83,13 @@ When defined, default parse and serialize functions for enums are excluded and h See [full documentation of `JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md). +## `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION` + +When defined to `1`, a JSON value can no longer be created from a one-element `std::tuple` holding a reference to a JSON +value, such as the result of `std::forward_as_tuple(j)`. This lets `std::tuple` convert such tuples element-wise. + +See [full documentation of `JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md). + ## `JSON_NO_IO` When defined, headers ``, ``, ``, ``, and `` are not included and parse functions diff --git a/docs/mkdocs/docs/integration/cmake.md b/docs/mkdocs/docs/integration/cmake.md index 71512cbd5..4160584d5 100644 --- a/docs/mkdocs/docs/integration/cmake.md +++ b/docs/mkdocs/docs/integration/cmake.md @@ -169,6 +169,12 @@ Enable position diagnostics by defining macro [`JSON_DIAGNOSTIC_POSITIONS`](../a Disable default `enum` serialization by defining the macro [`JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md). This option is `OFF` by default. +### `JSON_DisableTupleReferenceConversion` + +Disable the conversion from a one-element `std::tuple` holding a reference to a JSON value by defining the macro +[`JSON_DISABLE_TUPLE_REFERENCE_CONVERSION`](../api/macros/json_disable_tuple_reference_conversion.md). This option is +`OFF` by default. + ### `JSON_FastTests` Skip expensive/slow test suites. This option is `OFF` by default. Depends on `JSON_BuildTests`. diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index a05ce2dff..13bf44904 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -284,6 +284,7 @@ nav: - 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md - 'JSON_DIAGNOSTIC_POSITIONS': api/macros/json_diagnostic_positions.md - 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md + - 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md - 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20': api/macros/json_has_cpp_11.md - 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md - 'JSON_HAS_RANGES': api/macros/json_has_ranges.md diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 3a4eb79f4..45171de46 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -916,6 +916,10 @@ void templated_json_throw(ExceptionType exception) #define JSON_DISABLE_ENUM_SERIALIZATION 0 #endif +#ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION + #define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0 +#endif + #ifndef JSON_USE_GLOBAL_UDLS #define JSON_USE_GLOBAL_UDLS 1 #endif diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index a73951a22..5710193e2 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -25,6 +25,7 @@ #undef JSON_INLINE_VARIABLE #undef JSON_NO_UNIQUE_ADDRESS #undef JSON_DISABLE_ENUM_SERIALIZATION +#undef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION #undef JSON_USE_GLOBAL_UDLS #ifndef JSON_TEST_KEEP_MACROS diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 6f8bf2a3d..d9759fbcb 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -636,6 +636,18 @@ template struct is_compatible_type : is_compatible_type_impl {}; +// a one-element std::tuple holding a reference to BasicJsonType, as created by +// std::forward_as_tuple(j); see JSON_DISABLE_TUPLE_REFERENCE_CONVERSION +template +struct is_basic_json_reference_tuple : std::false_type {}; + +template +struct is_basic_json_reference_tuple> +{ + static constexpr bool value = + std::is_reference::value && std::is_same, BasicJsonType>::value; +}; + template struct is_compatible_binary_type { diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index abd461d6c..e677b54aa 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1595,7 +1595,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < typename CompatibleType, typename U = detail::uncvref_t, detail::enable_if_t < - !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > + !detail::is_basic_json::value && detail::is_compatible_type::value +#if JSON_DISABLE_TUPLE_REFERENCE_CONVERSION + // see https://github.com/nlohmann/json/issues/2226 + && !detail::is_basic_json_reference_tuple::value +#endif + , int > = 0 > basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) JSONSerializer::to_json(std::declval(), std::forward(val)))) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 81ddfb1c4..2f4a052a7 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3327,6 +3327,10 @@ void templated_json_throw(ExceptionType exception) #define JSON_DISABLE_ENUM_SERIALIZATION 0 #endif +#ifndef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION + #define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 0 +#endif + #ifndef JSON_USE_GLOBAL_UDLS #define JSON_USE_GLOBAL_UDLS 1 #endif @@ -4646,6 +4650,18 @@ template struct is_compatible_type : is_compatible_type_impl {}; +// a one-element std::tuple holding a reference to BasicJsonType, as created by +// std::forward_as_tuple(j); see JSON_DISABLE_TUPLE_REFERENCE_CONVERSION +template +struct is_basic_json_reference_tuple : std::false_type {}; + +template +struct is_basic_json_reference_tuple> +{ + static constexpr bool value = + std::is_reference::value && std::is_same, BasicJsonType>::value; +}; + template struct is_compatible_binary_type { @@ -26476,7 +26492,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < typename CompatibleType, typename U = detail::uncvref_t, detail::enable_if_t < - !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > + !detail::is_basic_json::value && detail::is_compatible_type::value +#if JSON_DISABLE_TUPLE_REFERENCE_CONVERSION + // see https://github.com/nlohmann/json/issues/2226 + && !detail::is_basic_json_reference_tuple::value +#endif + , int > = 0 > basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) JSONSerializer::to_json(std::declval(), std::forward(val)))) @@ -31465,6 +31486,7 @@ struct formatter // NOLINT(cert-dcl58-c #undef JSON_INLINE_VARIABLE #undef JSON_NO_UNIQUE_ADDRESS #undef JSON_DISABLE_ENUM_SERIALIZATION +#undef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION #undef JSON_USE_GLOBAL_UDLS #ifndef JSON_TEST_KEEP_MACROS diff --git a/tests/src/unit-disable-tuple-reference-conversion.cpp b/tests/src/unit-disable-tuple-reference-conversion.cpp new file mode 100644 index 000000000..913bca9f1 --- /dev/null +++ b/tests/src/unit-disable-tuple-reference-conversion.cpp @@ -0,0 +1,79 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include "doctest_compatibility.h" + +// This file tests the opt-in JSON_DISABLE_TUPLE_REFERENCE_CONVERSION, so it +// defines the macro itself rather than relying on a -D flag, and runs in every +// build. +#ifdef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION + #undef JSON_DISABLE_TUPLE_REFERENCE_CONVERSION +#endif + +#define JSON_DISABLE_TUPLE_REFERENCE_CONVERSION 1 + +#include +using nlohmann::json; +using nlohmann::ordered_json; + +#include +#include +#include +#include + +TEST_CASE("JSON_DISABLE_TUPLE_REFERENCE_CONVERSION") +{ + SECTION("json is not constructible from a one-element tuple of a json reference") + { + CHECK_FALSE(std::is_constructible>::value); + CHECK_FALSE(std::is_constructible>::value); + CHECK_FALSE(std::is_constructible < json, std::tuple < json && >>::value); + CHECK_FALSE(std::is_constructible&>::value); + CHECK_FALSE(std::is_constructible>::value); + } + + SECTION("issue #2226 - tuple from tuple keeps the reference") + { + json j = true; + const std::tuple tup(std::forward_as_tuple(j)); + CHECK(&std::get<0>(tup) == &j); + } + + SECTION("tuple from tuple copies the element") + { + const json j = {{"key", "value"}}; + const std::tuple t1(std::forward_as_tuple(j)); + CHECK(std::get<0>(t1) == j); + + json j2 = "text"; + const std::tuple t2(std::forward_as_tuple(std::move(j2))); + CHECK(std::get<0>(t2) == "text"); + } + + SECTION("other tuple conversions are not affected") + { + const json j = true; + + // one-element tuple holding a json value + CHECK(json(std::make_tuple(j)) == json::array({true})); + + // tuples with more than one element, even when holding references + int i = 1; + CHECK(json(std::forward_as_tuple(i, j)) == json::array({1, true})); + CHECK(json(std::forward_as_tuple(j, j)) == json::array({true, true})); + + // one-element tuples holding references to other types + std::string s = "text"; + CHECK(json(std::forward_as_tuple(s)) == json::array({"text"})); + CHECK(json(std::forward_as_tuple(i)) == json::array({1})); + + // a reference to a different basic_json specialization + ordered_json oj = true; + CHECK(json(std::forward_as_tuple(oj)) == json::array({true})); + } +} diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index b128b7a73..bdf852e00 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -18,6 +18,11 @@ // for some reason including this after the json header leads to linker errors with VS 2017... #include +// skip tests if JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1 (#2226) +#if defined(JSON_DISABLE_TUPLE_REFERENCE_CONVERSION) && (JSON_DISABLE_TUPLE_REFERENCE_CONVERSION == 1) + #define SKIP_TESTS_FOR_TUPLE_REFERENCE_CONVERSION +#endif + #define JSON_TESTS_PRIVATE #include using json = nlohmann::json; @@ -28,6 +33,7 @@ using ordered_json = nlohmann::ordered_json; #include #include +#include #include #include @@ -541,6 +547,18 @@ TEST_CASE("regression tests 2") ))); } +#ifndef SKIP_TESTS_FOR_TUPLE_REFERENCE_CONVERSION + SECTION("issue #2226 - std::tuple dangling reference - implicit conversion") + { + // by default, a one-element tuple holding a json reference converts to + // a one-element array; JSON_DISABLE_TUPLE_REFERENCE_CONVERSION removes + // this conversion (see unit-disable-tuple-reference-conversion.cpp) + const json j = true; + CHECK(std::is_constructible>::value); + CHECK(json(std::forward_as_tuple(j)) == json::array({true})); + } +#endif + SECTION("PR #2181 - regression bug with lvalue") { // see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060