Fix constraints on from_json() for strings (#3427)

Constrain from_json() overload for StringType to not accept json_ref and
require it to be assignable, instead of constructible, from
basic_json::string_t.

Re-enable C++14 tests on Clang <4.0.

Fixes #3171.
Fixes #3267.
Fixes #3312.
Fixes #3384.
This commit is contained in:
Florian Albrechtskirchinger 2022-04-08 10:22:47 +02:00 committed by GitHub
parent 15fa6a342a
commit 261cc4e509
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 17 deletions

View File

@ -105,13 +105,12 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
}
template <
typename BasicJsonType, typename ConstructibleStringType,
typename BasicJsonType, typename StringType,
enable_if_t <
is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value&&
!std::is_same<typename BasicJsonType::string_t,
ConstructibleStringType>::value,
int > = 0 >
void from_json(const BasicJsonType& j, ConstructibleStringType& s)
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
&& !std::is_same<typename BasicJsonType::string_t, StringType>::value
&& !is_json_ref<StringType>::value, int > = 0 >
void from_json(const BasicJsonType& j, StringType& s)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{

View File

@ -3928,13 +3928,12 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
}
template <
typename BasicJsonType, typename ConstructibleStringType,
typename BasicJsonType, typename StringType,
enable_if_t <
is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value&&
!std::is_same<typename BasicJsonType::string_t,
ConstructibleStringType>::value,
int > = 0 >
void from_json(const BasicJsonType& j, ConstructibleStringType& s)
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
&& !std::is_same<typename BasicJsonType::string_t, StringType>::value
&& !is_json_ref<StringType>::value, int > = 0 >
void from_json(const BasicJsonType& j, StringType& s)
{
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{

View File

@ -11,11 +11,6 @@ include(test)
# override standard support
#############################################################################
# compiling json.hpp in C++14 mode fails with Clang <4.0
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)
unset(compiler_supports_cpp_14)
endif()
# Clang only supports C++17 starting from Clang 5.0
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
unset(compiler_supports_cpp_17)

View File

@ -240,6 +240,50 @@ inline void from_json(const nlohmann::json& j, FooBar& fb)
j.at("value").get_to(fb.foo.value);
}
/////////////////////////////////////////////////////////////////////
// for #3171
/////////////////////////////////////////////////////////////////////
struct for_3171_base // NOLINT(cppcoreguidelines-special-member-functions)
{
for_3171_base(const std::string& /*unused*/ = {}) {}
virtual ~for_3171_base() = default;
virtual void _from_json(const json& j)
{
j.at("str").get_to(str);
}
std::string str{};
};
struct for_3171_derived : public for_3171_base
{
for_3171_derived() = default;
explicit for_3171_derived(const std::string& /*unused*/) { }
};
inline void from_json(const json& j, for_3171_base& tb)
{
tb._from_json(j);
}
/////////////////////////////////////////////////////////////////////
// for #3312
/////////////////////////////////////////////////////////////////////
#ifdef JSON_HAS_CPP_20
struct for_3312
{
std::string name;
};
inline void from_json(const json& j, for_3312& obj)
{
j.at("name").get_to(obj.name);
}
#endif
TEST_CASE("regression tests 2")
{
SECTION("issue #1001 - Fix memory leak during parser callback")
@ -791,6 +835,31 @@ TEST_CASE("regression tests 2")
CHECK(jit->first == ojit->first);
CHECK(jit->second.get<std::string>() == ojit->second.get<std::string>());
}
SECTION("issue #3171 - if class is_constructible from std::string wrong from_json overload is being selected, compilation failed")
{
json j{{ "str", "value"}};
// failed with: error: no match for operator= (operand types are for_3171_derived and const nlohmann::basic_json<>::string_t
// {aka const std::__cxx11::basic_string<char>})
// s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
auto td = j.get<for_3171_derived>();
CHECK(td.str == "value");
}
#ifdef JSON_HAS_CPP_20
SECTION("issue #3312 - Parse to custom class from unordered_json breaks on G++11.2.0 with C++20")
{
// see test for #3171
ordered_json j = {{"name", "class"}};
for_3312 obj{};
j.get_to(obj);
CHECK(obj.name == "class");
}
#endif
}
DOCTEST_CLANG_SUPPRESS_WARNING_POP