From d7d56febf0d8a55d7672fcdb16efc59e3985aa31 Mon Sep 17 00:00:00 2001 From: Piotr Kubaj Date: Sat, 19 Sep 2026 11:41:40 +0200 Subject: [PATCH] stream: make the variadic interface methods final InputStream.readf(...), OutputStream.printf(fmt, ...), writef(...) and writefln(...) are D-style variadic interface methods. For a class that implements the interface at a non-zero offset (Stream), LDC has to emit this-adjusting thunks for them and can only forward the variadic arguments with a `musttail` call. LLVM's PowerPC backend cannot honour `musttail` there, so compiling the library aborts on ppc64/ppc64le: LLVM ERROR: failed to perform tail call elimination on a call site marked musttail All four are thin forwarders to the non-variadic virtual methods (vreadf, vprintf, writefx). Make them `final` in the interfaces with those bodies and drop the identical copies from Stream: final interface methods are dispatched statically, so no thunk is generated. The API is unchanged and the methods remain callable through interface references; customisation still happens by overriding vreadf/vprintf/writefx. --- src/undead/stream.d | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/src/undead/stream.d b/src/undead/stream.d index 2fb2658..19816b8 100644 --- a/src/undead/stream.d +++ b/src/undead/stream.d @@ -230,7 +230,9 @@ interface InputStream { * -------------------------- */ int vreadf(TypeInfo[] arguments, va_list args); - int readf(...); /// ditto + final int readf(...) { /// ditto + return vreadf(_arguments, _argptr); + } /// Retrieve the number of bytes available for immediate reading. @property size_t available(); @@ -333,7 +335,13 @@ interface OutputStream { * returning the number of bytes written. */ size_t vprintf(const(char)[] format, va_list args); - size_t printf(const(char)[] format, ...); /// ditto + final size_t printf(const(char)[] format, ...) { /// ditto + va_list ap; + va_start(ap, format); + auto result = vprintf(format, ap); + va_end(ap); + return result; + } /*** * Print a formatted string into the stream using writef-style syntax. @@ -343,8 +351,12 @@ interface OutputStream { * NOTE: not supported in GDC, since it uses features unimplemented in that * compiler. */ - OutputStream writef(...); - OutputStream writefln(...); /// ditto + final OutputStream writef(...) { + return writefx(_arguments,_argptr,0); + } + final OutputStream writefln(...) { /// ditto + return writefx(_arguments,_argptr,1); + } OutputStream writefx(TypeInfo[] arguments, va_list argptr, int newline = false); /// ditto void flush(); /// Flush pending output if appropriate. @@ -1051,10 +1063,6 @@ class Stream : InputStream, OutputStream { return count; } - int readf(...) { - return vreadf(_arguments, _argptr); - } - // returns estimated number of bytes available for immediate reading @property size_t available() { return 0; } @@ -1181,32 +1189,12 @@ class Stream : InputStream, OutputStream { return count; } - // writes data to stream using printf() syntax, - // returns number of bytes written - size_t printf(const(char)[] format, ...) { - va_list ap; - va_start(ap, format); - auto result = vprintf(format, ap); - va_end(ap); - return result; - } - private void doFormatCallback(dchar c) { char[4] buf; auto b = undead.utf.toUTF8(buf, c); writeString(b); } - // writes data to stream using writef() syntax, - OutputStream writef(...) { - return writefx(_arguments,_argptr,0); - } - - // writes data with trailing newline - OutputStream writefln(...) { - return writefx(_arguments,_argptr,1); - } - // writes data with optional trailing newline OutputStream writefx(TypeInfo[] arguments, va_list argptr, int newline=false) { version (GNU)