diff --git a/std/format/internal/write.d b/std/format/internal/write.d index 480860862c2..716158168ff 100644 --- a/std/format/internal/write.d +++ b/std/format/internal/write.d @@ -3249,12 +3249,12 @@ if ((!is(StringTypeOf!T) || hasToString!(T, Char)) && !is(CharTypeOf!T) || is(T } // Fix for https://issues.dlang.org/show_bug.cgi?id=1591 -int getNthInt(string kind, A...)(uint index, A args) +int getNthInt(string kind, A...)(uint index, auto ref A args) { return getNth!(kind, isIntegral, int)(index, args); } -T getNth(string kind, alias Condition, T, A...)(uint index, A args) +T getNth(string kind, alias Condition, T, A...)(uint index, auto ref A args) { import std.conv : text, to; import std.format : FormatException; diff --git a/std/format/write.d b/std/format/write.d index 60ebe939093..c7eb8445447 100644 --- a/std/format/write.d +++ b/std/format/write.d @@ -524,7 +524,7 @@ Note: implementation there are some cases where allocations occur. See $(REF_ALTTEXT $(D sformat), sformat, std, format) for more details. */ -uint formattedWrite(Writer, Char, Args...)(auto ref Writer w, const scope Char[] fmt, Args args) +uint formattedWrite(Writer, Char, Args...)(auto ref Writer w, const scope Char[] fmt, auto ref Args args) { import std.conv : text; import std.format : enforceFmt, FormatException; diff --git a/std/stdio.d b/std/stdio.d index f3a1523eea1..a8cc072e18c 100644 --- a/std/stdio.d +++ b/std/stdio.d @@ -1677,46 +1677,46 @@ Writes its arguments in text format to the file. Throws: `Exception` if the file is not opened. `ErrnoException` on an error writing to the file. */ - void write(S...)(S args) + void write(S...)(auto ref S args) { import std.traits : isBoolean, isIntegral, isAggregateType; import std.utf : UTFException; auto w = lockingTextWriter(); - foreach (arg; args) + static foreach (i; 0 .. args.length) { try { - alias A = typeof(arg); + alias A = typeof(args[i]); static if (isAggregateType!A || is(A == enum)) { import std.format.write : formattedWrite; - formattedWrite(w, "%s", arg); + formattedWrite(w, "%s", args[i]); } else static if (isSomeString!A) { - put(w, arg); + put(w, args[i]); } else static if (isIntegral!A) { import std.conv : toTextRange; - toTextRange(arg, w); + toTextRange(args[i], w); } else static if (isBoolean!A) { - put(w, arg ? "true" : "false"); + put(w, args[i] ? "true" : "false"); } else static if (isSomeChar!A) { - put(w, arg); + put(w, args[i]); } else { import std.format.write : formattedWrite; // Most general case - formattedWrite(w, "%s", arg); + formattedWrite(w, "%s", args[i]); } } catch (UTFException e) @@ -1735,7 +1735,7 @@ Writes its arguments in text format to the file, followed by a newline. Throws: `Exception` if the file is not opened. `ErrnoException` on an error writing to the file. */ - void writeln(S...)(S args) + void writeln(S...)(auto ref S args) { write(args, '\n'); } @@ -1753,7 +1753,7 @@ args = Items to write. Throws: `Exception` if the file is not opened. `ErrnoException` on an error writing to the file. */ - void writef(alias fmt, A...)(A args) + void writef(alias fmt, A...)(auto ref A args) if (isSomeString!(typeof(fmt))) { import std.format : checkFormatException; @@ -1764,7 +1764,7 @@ Throws: `Exception` if the file is not opened. } /// ditto - void writef(Char, A...)(in Char[] fmt, A args) + void writef(Char, A...)(in Char[] fmt, auto ref A args) { import std.format.write : formattedWrite; @@ -1772,7 +1772,7 @@ Throws: `Exception` if the file is not opened. } /// Equivalent to `file.writef(fmt, args, '\n')`. - void writefln(alias fmt, A...)(A args) + void writefln(alias fmt, A...)(auto ref A args) if (isSomeString!(typeof(fmt))) { import std.format : checkFormatException; @@ -1783,7 +1783,7 @@ Throws: `Exception` if the file is not opened. } /// ditto - void writefln(Char, A...)(in Char[] fmt, A args) + void writefln(Char, A...)(in Char[] fmt, auto ref A args) { import std.format.write : formattedWrite; @@ -4137,7 +4137,7 @@ void main() } --- */ -void write(T...)(T args) +void write(T...)(auto ref T args) if (!is(T[0] : File)) { trustedStdout.write(args); @@ -4186,7 +4186,7 @@ void main() } --- */ -void writeln(T...)(T args) +void writeln(T...)(auto ref T args) { static if (T.length == 0) { @@ -4333,6 +4333,57 @@ void writeln(T...)(T args) useInit(stdout.lockingTextWriter()); } +// https://issues.dlang.org/show_bug.cgi?id=9489 +@system unittest +{ + static import std.file; + import std.typecons : scoped; + + auto deleteme = testFilename(); + auto f = File(deleteme, "w"); + scope(exit) { std.file.remove(deleteme); } + + class Foo + { + int x; + this(int x_) { this.x = x_; } + override string toString() { return "xxx"; } + } + + auto foo = scoped!Foo(100); + f.writeln(foo.x); + f.writeln(foo); + f.close(); + + version (Windows) + assert(cast(char[]) std.file.read(deleteme) == "100\r\nxxx\r\n"); + else + assert(cast(char[]) std.file.read(deleteme) == "100\nxxx\n"); +} + +// https://issues.dlang.org/show_bug.cgi?id=9489 (reduced test case) +@system unittest +{ + static import std.file; + + auto deleteme = testFilename(); + auto f = File(deleteme, "w"); + scope(exit) { std.file.remove(deleteme); } + + struct S + { + @disable this(this); + } + + S s; + f.writeln(s); + f.close(); + + version (Windows) + assert(cast(char[]) std.file.read(deleteme) == "S()\r\n"); + else + assert(cast(char[]) std.file.read(deleteme) == "S()\n"); +} /*********************************** Writes formatted data to standard output (without a trailing newline). @@ -4357,7 +4408,7 @@ stderr.writef("%s", "message"); ------ */ -void writef(alias fmt, A...)(A args) +void writef(alias fmt, A...)(auto ref A args) if (isSomeString!(typeof(fmt))) { import std.format : checkFormatException; @@ -4368,7 +4419,7 @@ if (isSomeString!(typeof(fmt))) } /// ditto -void writef(Char, A...)(in Char[] fmt, A args) +void writef(Char, A...)(in Char[] fmt, auto ref A args) { trustedStdout.writef(fmt, args); } @@ -4398,7 +4449,7 @@ void writef(Char, A...)(in Char[] fmt, A args) /*********************************** * Equivalent to $(D writef(fmt, args, '\n')). */ -void writefln(alias fmt, A...)(A args) +void writefln(alias fmt, A...)(auto ref A args) if (isSomeString!(typeof(fmt))) { import std.format : checkFormatException; @@ -4409,7 +4460,7 @@ if (isSomeString!(typeof(fmt))) } /// ditto -void writefln(Char, A...)(in Char[] fmt, A args) +void writefln(Char, A...)(in Char[] fmt, auto ref A args) { trustedStdout.writefln(fmt, args); }