diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp --- a/flang/runtime/edit-input.cpp +++ b/flang/runtime/edit-input.cpp @@ -248,7 +248,7 @@ int exponent{0}; int got{ScanRealInput(buffer, maxDigits + 2, io, edit, exponent)}; if (got >= maxDigits + 2) { - io.GetIoErrorHandler().Crash("EditRealInput: buffer was too small"); + io.GetIoErrorHandler().Crash("EditCommonRealInput: buffer was too small"); return false; } if (got == 0) { @@ -277,6 +277,8 @@ bool EditRealInput(IoStatementState &io, const DataEdit &edit, void *n) { switch (edit.descriptor) { case DataEdit::ListDirected: + case DataEdit::ListDirectedRealPart: + case DataEdit::ListDirectedImaginaryPart: case 'F': case 'E': // incl. EN, ES, & EX case 'D': diff --git a/flang/runtime/io-api.h b/flang/runtime/io-api.h --- a/flang/runtime/io-api.h +++ b/flang/runtime/io-api.h @@ -222,7 +222,9 @@ bool IONAME(OutputReal64)(Cookie, double); bool IONAME(InputReal64)(Cookie, double &); bool IONAME(OutputComplex32)(Cookie, float, float); +bool IONAME(InputComplex32)(Cookie, float[2]); bool IONAME(OutputComplex64)(Cookie, double, double); +bool IONAME(InputComplex64)(Cookie, double[2]); bool IONAME(OutputAscii)(Cookie, const char *, std::size_t); bool IONAME(InputAscii)(Cookie, char *, std::size_t); bool IONAME(OutputLogical)(Cookie, bool); diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -892,86 +892,101 @@ return false; } -bool IONAME(OutputReal32)(Cookie cookie, float x) { +template +static bool OutputReal(Cookie cookie, REAL x) { IoStatementState &io{*cookie}; if (!io.get_if()) { io.GetIoErrorHandler().Crash( - "OutputReal32() called for a non-output I/O statement"); + "OutputReal() called for a non-output I/O statement"); return false; } if (auto edit{io.GetNextDataEdit()}) { - return RealOutputEditing<24>{io, x}.Edit(*edit); + return RealOutputEditing{io, x}.Edit(*edit); } return false; } -bool IONAME(InputReal32)(Cookie cookie, float &x) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - io.GetIoErrorHandler().Crash( - "InputReal32() called for a non-input I/O statement"); - return false; - } - if (auto edit{io.GetNextDataEdit()}) { - if (edit->descriptor == DataEdit::ListDirectedNullValue) { - return true; - } - return EditRealInput<24>(io, *edit, reinterpret_cast(&x)); - } - return false; +bool IONAME(OutputReal32)(Cookie cookie, float x) { + return OutputReal<24, float>(cookie, x); } bool IONAME(OutputReal64)(Cookie cookie, double x) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - io.GetIoErrorHandler().Crash( - "OutputReal64() called for a non-output I/O statement"); - return false; - } - if (auto edit{io.GetNextDataEdit()}) { - return RealOutputEditing<53>{io, x}.Edit(*edit); - } - return false; + return OutputReal<53, double>(cookie, x); } -bool IONAME(InputReal64)(Cookie cookie, double &x) { +template +static bool InputReal(Cookie cookie, REAL &x) { IoStatementState &io{*cookie}; if (!io.get_if()) { io.GetIoErrorHandler().Crash( - "InputReal64() called for a non-input I/O statement"); + "InputReal() called for a non-input I/O statement"); return false; } if (auto edit{io.GetNextDataEdit()}) { if (edit->descriptor == DataEdit::ListDirectedNullValue) { return true; } - return EditRealInput<53>(io, *edit, reinterpret_cast(&x)); + return EditRealInput(io, *edit, reinterpret_cast(&x)); } return false; } -bool IONAME(OutputComplex32)(Cookie cookie, float r, float z) { +bool IONAME(InputReal32)(Cookie cookie, float &x) { + return InputReal<24, float>(cookie, x); +} + +bool IONAME(InputReal64)(Cookie cookie, double &x) { + return InputReal<53, double>(cookie, x); +} + +template +static bool OutputComplex(Cookie cookie, REAL r, REAL z) { IoStatementState &io{*cookie}; if (io.get_if>()) { DataEdit real, imaginary; real.descriptor = DataEdit::ListDirectedRealPart; imaginary.descriptor = DataEdit::ListDirectedImaginaryPart; - return RealOutputEditing<24>{io, r}.Edit(real) && - RealOutputEditing<24>{io, z}.Edit(imaginary); + return RealOutputEditing{io, r}.Edit(real) && + RealOutputEditing{io, z}.Edit(imaginary); } - return IONAME(OutputReal32)(cookie, r) && IONAME(OutputReal32)(cookie, z); + return OutputReal(cookie, r) && OutputReal(cookie, z); +} + +bool IONAME(OutputComplex32)(Cookie cookie, float r, float z) { + return OutputComplex<24, float>(cookie, r, z); } bool IONAME(OutputComplex64)(Cookie cookie, double r, double z) { + return OutputComplex<53, double>(cookie, r, z); +} + +template +static bool InputComplex(Cookie cookie, REAL x[2]) { IoStatementState &io{*cookie}; - if (io.get_if>()) { - DataEdit real, imaginary; - real.descriptor = DataEdit::ListDirectedRealPart; - imaginary.descriptor = DataEdit::ListDirectedImaginaryPart; - return RealOutputEditing<53>{io, r}.Edit(real) && - RealOutputEditing<53>{io, z}.Edit(imaginary); + if (!io.get_if()) { + io.GetIoErrorHandler().Crash( + "InputComplex() called for a non-input I/O statement"); + return false; + } + for (int j{0}; j < 2; ++j) { + if (auto edit{io.GetNextDataEdit()}) { + if (edit->descriptor == DataEdit::ListDirectedNullValue) { + return true; + } + if (!EditRealInput(io, *edit, reinterpret_cast(&x[j]))) { + return false; + } + } } - return IONAME(OutputReal64)(cookie, r) && IONAME(OutputReal64)(cookie, z); + return true; +} + +bool IONAME(InputComplex32)(Cookie cookie, float x[2]) { + return InputComplex<24, float>(cookie, x); +} + +bool IONAME(InputComplex64)(Cookie cookie, double x[2]) { + return InputComplex<53, double>(cookie, x); } bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) { diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp --- a/flang/runtime/io-stmt.cpp +++ b/flang/runtime/io-stmt.cpp @@ -509,6 +509,7 @@ } else if (realPart_) { realPart_ = false; imaginaryPart_ = true; + edit.descriptor = DataEdit::ListDirectedImaginaryPart; } if (!ch) { return std::nullopt; @@ -574,6 +575,7 @@ if (!imaginaryPart_ && ch && *ch == '(') { realPart_ = true; io.HandleRelativePosition(1); + edit.descriptor = DataEdit::ListDirectedRealPart; } return edit; } diff --git a/flang/unittests/Runtime/hello.cpp b/flang/unittests/Runtime/hello.cpp --- a/flang/unittests/Runtime/hello.cpp +++ b/flang/unittests/Runtime/hello.cpp @@ -81,6 +81,43 @@ } } +static void listInputTest() { + static const char input[]{",1*,(5.,6..)"}; + auto cookie{IONAME(BeginInternalListInput)(input, sizeof input - 1)}; + float z[6]; + for (int j{0}; j < 6; ++j) { + z[j] = -(j + 1); + } + for (int j{0}; j < 6; j += 2) { + if (!IONAME(InputComplex32)(cookie, &z[j])) { + Fail() << "InputComplex32 failed\n"; + } + } + auto status{IONAME(EndIoStatement)(cookie)}; + if (status) { + Fail() << "Failed complex list-directed input, status " + << static_cast(status) << '\n'; + } else { + char output[33]; + output[32] = '\0'; + cookie = IONAME(BeginInternalListOutput)(output, 32); + for (int j{0}; j < 6; j += 2) { + if (!IONAME(OutputComplex32)(cookie, z[j], z[j + 1])) { + Fail() << "OutputComplex32 failed\n"; + } + } + status = IONAME(EndIoStatement)(cookie); + static const char expect[33]{" (-1.,-2.) (-3.,-4.) (5.,6.) "}; + if (status) { + Fail() << "Failed complex list-directed output, status " + << static_cast(status) << '\n'; + } else if (std::strncmp(output, expect, 33) != 0) { + Fail() << "Failed complex list-directed output, expected '" << expect + << "', but got '" << output << "'\n"; + } + } +} + static void realTest(const char *format, double x, const char *expect) { char buffer[800]; auto cookie{IONAME(BeginInternalFormattedOutput)( @@ -444,5 +481,7 @@ realInTest("(BZ,F18.0)", " 125 ", 0x4093880000000000); // 1250 realInTest("(DC,F18.0)", " 12,5", 0x4029000000000000); + listInputTest(); + return EndTests(); }