From 01d611882884c8cd94b576342b1f7733f397c5b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= <theo.delrieu@tanker.io>
Date: Mon, 12 Feb 2018 10:47:17 +0100
Subject: [PATCH] Fix constraints on from_json(CompatibleArrayType)

Fixes #924
---
 .../nlohmann/detail/conversions/from_json.hpp | 16 +++++++++-----
 single_include/nlohmann/json.hpp              | 16 +++++++++-----
 test/src/unit-inspection.cpp                  |  4 ++--
 test/src/unit-udt.cpp                         | 22 +++++++++++++++++++
 4 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp
index 8ea0284a..eccc04f1 100644
--- a/include/nlohmann/detail/conversions/from_json.hpp
+++ b/include/nlohmann/detail/conversions/from_json.hpp
@@ -177,15 +177,21 @@ void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priorit
     }
 }
 
-template<typename BasicJsonType, typename CompatibleArrayType,
-         enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
-                     std::is_convertible<BasicJsonType, typename CompatibleArrayType::value_type>::value and
-                     not std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, int> = 0>
+template <
+    typename BasicJsonType, typename CompatibleArrayType,
+    enable_if_t <
+        is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
+        not std::is_same<typename BasicJsonType::array_t,
+                         CompatibleArrayType>::value and
+        std::is_constructible <
+            BasicJsonType, typename CompatibleArrayType::value_type >::value,
+        int > = 0 >
 void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
 {
     if (JSON_UNLIKELY(not j.is_array()))
     {
-        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
+        JSON_THROW(type_error::create(302, "type must be array, but is " +
+                                      std::string(j.type_name())));
     }
 
     from_json_array_impl(j, arr, priority_tag<2> {});
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index a7c009c0..c7530586 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -1084,15 +1084,21 @@ void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priorit
     }
 }
 
-template<typename BasicJsonType, typename CompatibleArrayType,
-         enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
-                     std::is_convertible<BasicJsonType, typename CompatibleArrayType::value_type>::value and
-                     not std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, int> = 0>
+template <
+    typename BasicJsonType, typename CompatibleArrayType,
+    enable_if_t <
+        is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
+        not std::is_same<typename BasicJsonType::array_t,
+                         CompatibleArrayType>::value and
+        std::is_constructible <
+            BasicJsonType, typename CompatibleArrayType::value_type >::value,
+        int > = 0 >
 void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
 {
     if (JSON_UNLIKELY(not j.is_array()))
     {
-        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
+        JSON_THROW(type_error::create(302, "type must be array, but is " +
+                                      std::string(j.type_name())));
     }
 
     from_json_array_impl(j, arr, priority_tag<2> {});
diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp
index 5facb116..4bee80d1 100644
--- a/test/src/unit-inspection.cpp
+++ b/test/src/unit-inspection.cpp
@@ -316,8 +316,8 @@ TEST_CASE("object inspection")
     SECTION("round trips")
     {
         for (const auto& s :
-                {"3.141592653589793", "1000000000000000010E5"
-                })
+    {"3.141592653589793", "1000000000000000010E5"
+    })
         {
             json j1 = json::parse(s);
             std::string s1 = j1.dump();
diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp
index 17baf4e5..65ca788a 100644
--- a/test/src/unit-udt.cpp
+++ b/test/src/unit-udt.cpp
@@ -711,3 +711,25 @@ TEST_CASE("an incomplete type does not trigger a compiler error in non-evaluated
 {
     static_assert(not is_constructible_patched<json, incomplete>::value, "");
 }
+
+namespace
+{
+class Evil
+{
+  public:
+    Evil() = default;
+    template <typename T>
+    Evil(T) {}
+};
+
+void from_json(const json&, Evil&) {}
+}
+
+TEST_CASE("Issue #924")
+{
+    // Prevent get<std::vector<Evil>>() to throw
+    auto j = json::array();
+
+    (void) j.get<Evil>();
+    (void) j.get<std::vector<Evil>>();
+}