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 @@ -231,10 +231,12 @@ // and avoid the following items when they might crash. bool IONAME(OutputDescriptor)(Cookie, const Descriptor &); bool IONAME(InputDescriptor)(Cookie, const Descriptor &); +// Contiguous transfers for unformatted I/O bool IONAME(OutputUnformattedBlock)( Cookie, const char *, std::size_t, std::size_t elementBytes); bool IONAME(InputUnformattedBlock)( Cookie, char *, std::size_t, std::size_t elementBytes); +// Formatted (including list directed) I/O data items bool IONAME(OutputInteger64)(Cookie, std::int64_t); bool IONAME(InputInteger)(Cookie, std::int64_t &, int kind = 8); bool IONAME(OutputReal32)(Cookie, float); @@ -245,7 +247,9 @@ bool IONAME(InputComplex32)(Cookie, float[2]); bool IONAME(OutputComplex64)(Cookie, double, double); bool IONAME(InputComplex64)(Cookie, double[2]); +bool IONAME(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1); bool IONAME(OutputAscii)(Cookie, const char *, std::size_t); +bool IONAME(InputCharacter)(Cookie, char *, std::size_t, int kind = 1); bool IONAME(InputAscii)(Cookie, char *, std::size_t); bool IONAME(OutputLogical)(Cookie, bool); bool IONAME(InputLogical)(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 @@ -922,14 +922,16 @@ } bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) { + cookie->CheckFormattedStmtType("OutputInteger64"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish( - TypeCategory::Integer, 8, reinterpret_cast(&n), 0); + TypeCategory::Integer, sizeof n, reinterpret_cast(&n), 0); return descr::DescriptorIO(*cookie, descriptor); } bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) { + cookie->CheckFormattedStmtType("InputInteger"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish( @@ -938,6 +940,7 @@ } bool IONAME(OutputReal32)(Cookie cookie, float x) { + cookie->CheckFormattedStmtType("OutputReal32"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast(&x), 0); @@ -945,6 +948,7 @@ } bool IONAME(OutputReal64)(Cookie cookie, double x) { + cookie->CheckFormattedStmtType("OutputReal64"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast(&x), 0); @@ -952,6 +956,7 @@ } bool IONAME(InputReal32)(Cookie cookie, float &x) { + cookie->CheckFormattedStmtType("InputReal32"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast(&x), 0); @@ -959,6 +964,7 @@ } bool IONAME(InputReal64)(Cookie cookie, double &x) { + cookie->CheckFormattedStmtType("InputReal64"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast(&x), 0); @@ -966,6 +972,7 @@ } bool IONAME(OutputComplex32)(Cookie cookie, float r, float i) { + cookie->CheckFormattedStmtType("OutputComplex32"); float z[2]{r, i}; StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; @@ -975,6 +982,7 @@ } bool IONAME(OutputComplex64)(Cookie cookie, double r, double i) { + cookie->CheckFormattedStmtType("OutputComplex64"); double z[2]{r, i}; StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; @@ -984,6 +992,7 @@ } bool IONAME(InputComplex32)(Cookie cookie, float z[2]) { + cookie->CheckFormattedStmtType("InputComplex32"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish( @@ -992,6 +1001,7 @@ } bool IONAME(InputComplex64)(Cookie cookie, double z[2]) { + cookie->CheckFormattedStmtType("InputComplex64"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish( @@ -999,34 +1009,48 @@ return descr::DescriptorIO(*cookie, descriptor); } -bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) { +bool IONAME(OutputCharacter)( + Cookie cookie, const char *x, std::size_t length, int kind) { + cookie->CheckFormattedStmtType("OutputCharacter"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish( - 1, length, reinterpret_cast(const_cast(x)), 0); + kind, length, reinterpret_cast(const_cast(x)), 0); return descr::DescriptorIO(*cookie, descriptor); } -bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) { +bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) { + return IONAME(OutputCharacter(cookie, x, length, 1)); +} + +bool IONAME(InputCharacter)( + Cookie cookie, char *x, std::size_t length, int kind) { + cookie->CheckFormattedStmtType("InputCharacter"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; - descriptor.Establish(1, length, reinterpret_cast(x), 0); + descriptor.Establish(kind, length, reinterpret_cast(x), 0); return descr::DescriptorIO(*cookie, descriptor); } +bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) { + return IONAME(InputCharacter(cookie, x, length, 1)); +} + bool IONAME(OutputLogical)(Cookie cookie, bool truth) { + cookie->CheckFormattedStmtType("OutputLogical"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish( - TypeCategory::Logical, 1, reinterpret_cast(&truth), 0); + TypeCategory::Logical, sizeof truth, reinterpret_cast(&truth), 0); return descr::DescriptorIO(*cookie, descriptor); } bool IONAME(InputLogical)(Cookie cookie, bool &truth) { + cookie->CheckFormattedStmtType("InputLogical"); StaticDescriptor staticDescriptor; Descriptor &descriptor{staticDescriptor.descriptor()}; descriptor.Establish( - TypeCategory::Logical, 1, reinterpret_cast(&truth), 0); + TypeCategory::Logical, sizeof truth, reinterpret_cast(&truth), 0); return descr::DescriptorIO(*cookie, descriptor); } diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h --- a/flang/runtime/io-stmt.h +++ b/flang/runtime/io-stmt.h @@ -43,6 +43,13 @@ template class ExternalListIoStatementState; template class UnformattedIoStatementState; +struct InputStatementState {}; +struct OutputStatementState {}; +template +using IoDirectionState = std::conditional_t; +struct FormattedIoStatementState {}; + // The Cookie type in the I/O API is a pointer (for C) to this class. class IoStatementState { public: @@ -90,6 +97,15 @@ std::optional NextInField(std::optional &remaining); std::optional GetNextNonBlank(); // can advance record + template void CheckFormattedStmtType(const char *name) { + if (!get_if() || + !get_if>()) { + GetIoErrorHandler().Crash( + "%s called for I/O statement that is not formatted %s", name, + D == Direction::Output ? "output" : "input"); + } + } + private: std::variant, std::reference_wrapper, @@ -132,17 +148,11 @@ void BadInquiryKeywordHashCrash(InquiryKeywordHash); }; -struct InputStatementState {}; -struct OutputStatementState {}; -template -using IoDirectionState = std::conditional_t; - -struct FormattedStatementState {}; - // Common state for list-directed internal & external I/O -template struct ListDirectedStatementState {}; -template <> struct ListDirectedStatementState { +template struct ListDirectedStatementState; +template <> +struct ListDirectedStatementState + : public FormattedIoStatementState { static std::size_t RemainingSpaceInRecord(const ConnectionState &); bool NeedAdvance(const ConnectionState &, std::size_t) const; bool EmitLeadingSpaceOrAdvance( @@ -151,7 +161,9 @@ IoStatementState &, int maxRepeat = 1); bool lastWasUndelimitedCharacter{false}; }; -template <> class ListDirectedStatementState { +template <> +class ListDirectedStatementState + : public FormattedIoStatementState { public: // Skips value separators, handles repetition and null values. // Vacant when '/' appears; present with descriptor == ListDirectedNullValue @@ -199,7 +211,7 @@ template class InternalFormattedIoStatementState : public InternalIoStatementState, - public FormattedStatementState { + public FormattedIoStatementState { public: using CharType = CHAR; using typename InternalIoStatementState::Buffer; @@ -275,7 +287,7 @@ template class ExternalFormattedIoStatementState : public ExternalIoStatementState, - public FormattedStatementState { + public FormattedIoStatementState { public: using CharType = CHAR; ExternalFormattedIoStatementState(ExternalFileUnit &, const CharType *format, diff --git a/flang/runtime/type-code.cpp b/flang/runtime/type-code.cpp --- a/flang/runtime/type-code.cpp +++ b/flang/runtime/type-code.cpp @@ -78,13 +78,13 @@ raw_ = CFI_type_Bool; break; case 2: - raw_ = CFI_type_int16_t; + raw_ = CFI_type_int_fast16_t; break; case 4: - raw_ = CFI_type_int32_t; + raw_ = CFI_type_int_fast32_t; break; case 8: - raw_ = CFI_type_int64_t; + raw_ = CFI_type_int_fast64_t; break; } break; diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -290,7 +290,7 @@ furthestPositionInRecord = furthestAfter; return true; } else { - handler.SignalEnd(); + // EOF or error: can be handled & has been signaled endfileRecordNumber = currentRecordNumber; return false; }