Skip to content

Commit cd0a122

Browse files
committed
[flang] Fix "non-advancing" I/O, support $ in FORMAT
Non-advancing I/O was failing; ExternalFileUnit was losing track of what writes had been committed to the file. Fixed. Also, support the common extension of $ and \ in a FORMAT as being equivalent to ADVANCE=NO. Differential Revision: https://reviews.llvm.org/D105046
1 parent e837ce2 commit cd0a122

File tree

9 files changed

+60
-30
lines changed

9 files changed

+60
-30
lines changed

flang/runtime/connection.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ struct ConnectionState : public ConnectionAttributes {
4949
std::int64_t currentRecordNumber{1}; // 1 is first
5050
std::int64_t positionInRecord{0}; // offset in current record
5151
std::int64_t furthestPositionInRecord{0}; // max(position+bytes)
52-
bool nonAdvancing{false}; // ADVANCE='NO'
5352

5453
// Set at end of non-advancing I/O data transfer
5554
std::optional<std::int64_t> leftTabLimit; // offset in current record

flang/runtime/format-implementation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
357357
}
358358
} else if (ch == '/') {
359359
context.AdvanceRecord(repeat && *repeat > 0 ? *repeat : 1);
360+
} else if (ch == '$' || ch == '\\') {
361+
context.mutableModes().nonAdvancing = true;
360362
} else {
361363
context.SignalError(IostatErrorInFormat,
362364
"Invalid character '%c' in FORMAT", static_cast<char>(ch));

flang/runtime/format.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct MutableModes {
3535
char delim{'\0'}; // DELIM=
3636
short scale{0}; // kP
3737
bool inNamelist{false}; // skip ! comments
38+
bool nonAdvancing{false}; // ADVANCE='NO', or $ or \ in FORMAT
3839
};
3940

4041
// A single edit descriptor extracted from a FORMAT

flang/runtime/io-api.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -437,12 +437,13 @@ static bool YesOrNo(const char *keyword, std::size_t length, const char *what,
437437
bool IONAME(SetAdvance)(
438438
Cookie cookie, const char *keyword, std::size_t length) {
439439
IoStatementState &io{*cookie};
440-
ConnectionState &connection{io.GetConnectionState()};
441-
connection.nonAdvancing =
442-
!YesOrNo(keyword, length, "ADVANCE", io.GetIoErrorHandler());
443-
if (connection.nonAdvancing && connection.access == Access::Direct) {
440+
bool nonAdvancing{
441+
!YesOrNo(keyword, length, "ADVANCE", io.GetIoErrorHandler())};
442+
if (nonAdvancing && io.GetConnectionState().access == Access::Direct) {
444443
io.GetIoErrorHandler().SignalError(
445444
"Non-advancing I/O attempted on direct access file");
445+
} else {
446+
io.mutableModes().nonAdvancing = nonAdvancing;
446447
}
447448
return true;
448449
}

flang/runtime/io-stmt.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,8 @@ MutableModes &ExternalIoStatementBase::mutableModes() { return unit_.modes; }
203203
ConnectionState &ExternalIoStatementBase::GetConnectionState() { return unit_; }
204204

205205
int ExternalIoStatementBase::EndIoStatement() {
206-
if (unit_.nonAdvancing) {
206+
if (mutableModes().nonAdvancing) {
207207
unit_.leftTabLimit = unit_.furthestPositionInRecord;
208-
unit_.nonAdvancing = false;
209208
} else {
210209
unit_.leftTabLimit.reset();
211210
}
@@ -260,14 +259,20 @@ int NoUnitIoStatementState::EndIoStatement() {
260259
return result;
261260
}
262261

262+
template <Direction DIR>
263+
ExternalIoStatementState<DIR>::ExternalIoStatementState(
264+
ExternalFileUnit &unit, const char *sourceFile, int sourceLine)
265+
: ExternalIoStatementBase{unit, sourceFile, sourceLine}, mutableModes_{
266+
unit.modes} {}
267+
263268
template <Direction DIR> int ExternalIoStatementState<DIR>::EndIoStatement() {
264269
if constexpr (DIR == Direction::Input) {
265270
BeginReadingRecord(); // in case there were no I/O items
266-
if (!unit().nonAdvancing) {
271+
if (!mutableModes().nonAdvancing) {
267272
FinishReadingRecord();
268273
}
269274
} else {
270-
if (!unit().nonAdvancing) {
275+
if (!mutableModes().nonAdvancing) {
271276
unit().AdvanceRecord(*this);
272277
}
273278
unit().FlushIfTerminal(*this);
@@ -375,7 +380,7 @@ ExternalFormattedIoStatementState<DIR, CHAR>::ExternalFormattedIoStatementState(
375380
ExternalFileUnit &unit, const CHAR *format, std::size_t formatLength,
376381
const char *sourceFile, int sourceLine)
377382
: ExternalIoStatementState<DIR>{unit, sourceFile, sourceLine},
378-
mutableModes_{unit.modes}, format_{*this, format, formatLength} {}
383+
format_{*this, format, formatLength} {}
379384

380385
template <Direction DIR, typename CHAR>
381386
int ExternalFormattedIoStatementState<DIR, CHAR>::EndIoStatement() {
@@ -558,7 +563,7 @@ std::optional<char32_t> IoStatementState::NextInField(
558563
return std::optional<char32_t>{' '};
559564
}
560565
IoErrorHandler &handler{GetIoErrorHandler()};
561-
if (connection.nonAdvancing) {
566+
if (mutableModes().nonAdvancing) {
562567
handler.SignalEor();
563568
} else {
564569
handler.SignalError(IostatRecordReadOverrun);
@@ -867,7 +872,7 @@ int ExternalMiscIoStatementState::EndIoStatement() {
867872
ExternalFileUnit &ext{unit()};
868873
switch (which_) {
869874
case Flush:
870-
ext.Flush(*this);
875+
ext.FlushOutput(*this);
871876
std::fflush(nullptr); // flushes C stdio output streams (12.9(2))
872877
break;
873878
case Backspace:

flang/runtime/io-stmt.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,9 @@ template <Direction DIR>
320320
class ExternalIoStatementState : public ExternalIoStatementBase,
321321
public IoDirectionState<DIR> {
322322
public:
323-
using ExternalIoStatementBase::ExternalIoStatementBase;
323+
ExternalIoStatementState(
324+
ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
325+
MutableModes &mutableModes() { return mutableModes_; }
324326
int EndIoStatement();
325327
bool Emit(const char *, std::size_t, std::size_t elementBytes);
326328
bool Emit(const char *, std::size_t);
@@ -333,6 +335,12 @@ class ExternalIoStatementState : public ExternalIoStatementBase,
333335
void HandleAbsolutePosition(std::int64_t);
334336
bool BeginReadingRecord();
335337
void FinishReadingRecord();
338+
339+
private:
340+
// These are forked from ConnectionState's modes at the beginning
341+
// of each formatted I/O statement so they may be overridden by control
342+
// edit descriptors during the statement.
343+
MutableModes mutableModes_;
336344
};
337345

338346
template <Direction DIR, typename CHAR>
@@ -343,18 +351,13 @@ class ExternalFormattedIoStatementState : public ExternalIoStatementState<DIR>,
343351
ExternalFormattedIoStatementState(ExternalFileUnit &, const CharType *format,
344352
std::size_t formatLength, const char *sourceFile = nullptr,
345353
int sourceLine = 0);
346-
MutableModes &mutableModes() { return mutableModes_; }
347354
int EndIoStatement();
348355
std::optional<DataEdit> GetNextDataEdit(
349356
IoStatementState &, int maxRepeat = 1) {
350357
return format_.GetNextDataEdit(*this, maxRepeat);
351358
}
352359

353360
private:
354-
// These are forked from ConnectionState's modes at the beginning
355-
// of each formatted I/O statement so they may be overridden by control
356-
// edit descriptors during the statement.
357-
MutableModes mutableModes_;
358361
FormatControl<ExternalFormattedIoStatementState> format_;
359362
};
360363

flang/runtime/unit-map.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void UnitMap::FlushAll(IoErrorHandler &handler) {
6767
CriticalSection critical{lock_};
6868
for (int j{0}; j < buckets_; ++j) {
6969
for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) {
70-
p->unit.Flush(handler);
70+
p->unit.FlushOutput(handler);
7171
}
7272
}
7373
}

flang/runtime/unit.cpp

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void FlushOutputOnCrash(const Terminator &terminator) {
3232
if (defaultOutput) {
3333
IoErrorHandler handler{terminator};
3434
handler.HasIoStat(); // prevent nested crash if flush has error
35-
defaultOutput->Flush(handler);
35+
defaultOutput->FlushOutput(handler);
3636
}
3737
}
3838

@@ -118,7 +118,7 @@ void ExternalFileUnit::OpenUnit(std::optional<OpenStatus> status,
118118
}
119119
// Otherwise, OPEN on open unit with new FILE= implies CLOSE
120120
DoImpliedEndfile(handler);
121-
Flush(handler);
121+
FlushOutput(handler);
122122
Close(CloseStatus::Keep, handler);
123123
}
124124
set_path(std::move(newPath), newPathLength);
@@ -168,7 +168,7 @@ void ExternalFileUnit::OpenAnonymousUnit(std::optional<OpenStatus> status,
168168

169169
void ExternalFileUnit::CloseUnit(CloseStatus status, IoErrorHandler &handler) {
170170
DoImpliedEndfile(handler);
171-
Flush(handler);
171+
FlushOutput(handler);
172172
Close(status, handler);
173173
}
174174

@@ -462,12 +462,9 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
462462
ok = ok && Emit("\n", 1, 1, handler); // TODO: Windows CR+LF
463463
}
464464
}
465-
frameOffsetInFile_ +=
466-
recordOffsetInFrame_ + recordLength.value_or(furthestPositionInRecord);
467-
recordOffsetInFrame_ = 0;
465+
CommitWrites();
468466
impliedEndfile_ = true;
469467
++currentRecordNumber;
470-
BeginRecord();
471468
return ok;
472469
}
473470
}
@@ -499,9 +496,24 @@ void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) {
499496
}
500497
}
501498

499+
void ExternalFileUnit::FlushOutput(IoErrorHandler &handler) {
500+
if (!mayPosition()) {
501+
auto frameAt{FrameAt()};
502+
if (frameOffsetInFile_ >= frameAt &&
503+
frameOffsetInFile_ <
504+
static_cast<std::int64_t>(frameAt + FrameLength())) {
505+
// A Flush() that's about to happen to a non-positionable file
506+
// needs to advance frameOffsetInFile_ to prevent attempts at
507+
// impossible seeks
508+
CommitWrites();
509+
}
510+
}
511+
Flush(handler);
512+
}
513+
502514
void ExternalFileUnit::FlushIfTerminal(IoErrorHandler &handler) {
503515
if (isTerminal()) {
504-
Flush(handler);
516+
FlushOutput(handler);
505517
}
506518
}
507519

@@ -533,8 +545,6 @@ void ExternalFileUnit::Rewind(IoErrorHandler &handler) {
533545
}
534546

535547
void ExternalFileUnit::EndIoStatement() {
536-
frameOffsetInFile_ += recordOffsetInFrame_;
537-
recordOffsetInFrame_ = 0;
538548
io_.reset();
539549
u_.emplace<std::monostate>();
540550
lock_.Drop();
@@ -585,7 +595,7 @@ void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
585595
void ExternalFileUnit::BeginSequentialVariableFormattedInputRecord(
586596
IoErrorHandler &handler) {
587597
if (this == defaultInput && defaultOutput) {
588-
defaultOutput->Flush(handler);
598+
defaultOutput->FlushOutput(handler);
589599
}
590600
std::size_t length{0};
591601
do {
@@ -701,6 +711,13 @@ void ExternalFileUnit::DoEndfile(IoErrorHandler &handler) {
701711
impliedEndfile_ = false;
702712
}
703713

714+
void ExternalFileUnit::CommitWrites() {
715+
frameOffsetInFile_ +=
716+
recordOffsetInFrame_ + recordLength.value_or(furthestPositionInRecord);
717+
recordOffsetInFrame_ = 0;
718+
BeginRecord();
719+
}
720+
704721
ChildIo &ExternalFileUnit::PushChildIo(IoStatementState &parent) {
705722
OwningPtr<ChildIo> current{std::move(child_)};
706723
Terminator &terminator{parent.GetIoErrorHandler()};

flang/runtime/unit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class ExternalFileUnit : public ConnectionState,
8282
void FinishReadingRecord(IoErrorHandler &);
8383
bool AdvanceRecord(IoErrorHandler &);
8484
void BackspaceRecord(IoErrorHandler &);
85+
void FlushOutput(IoErrorHandler &);
8586
void FlushIfTerminal(IoErrorHandler &);
8687
void Endfile(IoErrorHandler &);
8788
void Rewind(IoErrorHandler &);
@@ -107,6 +108,7 @@ class ExternalFileUnit : public ConnectionState,
107108
bool SetSequentialVariableFormattedRecordLength();
108109
void DoImpliedEndfile(IoErrorHandler &);
109110
void DoEndfile(IoErrorHandler &);
111+
void CommitWrites();
110112

111113
int unitNumber_{-1};
112114
Direction direction_{Direction::Output};

0 commit comments

Comments
 (0)