From 3e26069a4f7383e02e12df35f4b92cfa4ac113a4 Mon Sep 17 00:00:00 2001 From: Mathis Beer Date: Thu, 16 Jan 2020 16:20:37 +0100 Subject: [PATCH] Fix issue 20511: make toJSON infer safeness based on output range safeness. --- std/json.d | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/std/json.d b/std/json.d index 3d69504bb0b..128bfcba395 100644 --- a/std/json.d +++ b/std/json.d @@ -1399,10 +1399,10 @@ void toJSON(Out)( auto ref Out json, const ref JSONValue root, in bool pretty = false, - in JSONOptions options = JSONOptions.none) @safe + in JSONOptions options = JSONOptions.none) if (isOutputRange!(Out,char)) { - void toStringImpl(Char)(string str) @safe + void toStringImpl(Char)(string str) { json.put('"'); @@ -1463,7 +1463,7 @@ if (isOutputRange!(Out,char)) json.put('"'); } - void toString(string str) @safe + void toString(string str) { // Avoid UTF decoding when possible, as it is unnecessary when // processing JSON. @@ -1473,7 +1473,19 @@ if (isOutputRange!(Out,char)) toStringImpl!char(str); } - void toValue(ref const JSONValue value, ulong indentLevel) @safe + // recursive @safe inference is broken here + // workaround: if json.put is @safe, we should be too, + // so annotate the recursion as @safe manually + static if (isSafe!({ json.put(""); })) + { + void delegate(ref const JSONValue, ulong) @safe toValue; + } + else + { + void delegate(ref const JSONValue, ulong) @system toValue; + } + + void toValueImpl(ref const JSONValue value, ulong indentLevel) { void putTabs(ulong additionalIndent = 0) { @@ -1629,6 +1641,8 @@ if (isOutputRange!(Out,char)) } } + toValue = &toValueImpl; + toValue(root, 0); } @@ -1646,6 +1660,15 @@ if (isOutputRange!(Out,char)) assert(toJSON(jv1, false, JSONOptions.none) == `"été"`); } +@system unittest // bugzilla 20511 +{ + import std.format : formattedWrite; + import std.range : nullSink, outputRangeObject; + + outputRangeObject!(const(char)[])(nullSink) + .formattedWrite!"%s"(JSONValue.init); +} + /** Exception thrown on JSON errors */