Skip to content

Commit 115d6b5

Browse files
author
git apple-llvm automerger
committed
Merge commit '673e3051b0ed' from llvm.org/main into next
2 parents cfc0df9 + 673e305 commit 115d6b5

File tree

6 files changed

+65
-19
lines changed

6 files changed

+65
-19
lines changed

flang-rt/include/flang-rt/runtime/io-error.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ class IoErrorHandler : public Terminator {
6767
RT_API_ATTRS int GetIoStat() const { return ioStat_; }
6868
RT_API_ATTRS bool GetIoMsg(char *, std::size_t);
6969

70+
// Sets the HasEnd flag so that EOF isn't fatal; used to peek ahead
71+
RT_API_ATTRS bool SetHasEnd(bool yes = true) {
72+
bool oldValue{(flags_ & hasEnd) != 0};
73+
if (yes) {
74+
flags_ |= hasEnd;
75+
} else {
76+
flags_ &= ~hasEnd;
77+
}
78+
return oldValue;
79+
}
80+
7081
private:
7182
enum Flag : std::uint8_t {
7283
hasIoStat = 1, // IOSTAT=

flang-rt/include/flang-rt/runtime/io-stmt.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,13 @@ class ChildListIoStatementState : public ChildIoStatementState<DIR>,
703703
using ListDirectedStatementState<DIR>::GetNextDataEdit;
704704
RT_API_ATTRS bool AdvanceRecord(int = 1);
705705
RT_API_ATTRS int EndIoStatement();
706+
RT_API_ATTRS bool CanAdvance() {
707+
return DIR == Direction::Input &&
708+
(canAdvance_ || this->mutableModes().inNamelist);
709+
}
710+
711+
private:
712+
bool canAdvance_{false};
706713
};
707714

708715
template <Direction DIR>

flang-rt/lib/runtime/descriptor-io.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ static RT_API_ATTRS common::optional<bool> DefinedFormattedIo(
4747
const typeInfo::DerivedType &derived,
4848
const typeInfo::SpecialBinding &special,
4949
const SubscriptValue subscripts[]) {
50-
// Look at the next data edit descriptor. If this is list-directed I/O, the
51-
// "maxRepeat=0" argument will prevent the input from advancing over an
50+
// Look at the next data edit descriptor. If this is list-directed input,
51+
// the "maxRepeat=0" argument will prevent the input from advancing over an
5252
// initial '(' that shouldn't be consumed now as the start of a real part.
53+
// It also allows reaching EOF without crashing, since the EOF only matters
54+
// if a child READ is actually performed.
5355
common::optional<DataEdit> peek{io.GetNextDataEdit(/*maxRepeat=*/0)};
5456
if (peek &&
5557
(peek->descriptor == DataEdit::DefinedDerivedType ||

flang-rt/lib/runtime/edit-input.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,13 @@ static RT_API_ATTRS bool EditBOZInput(
5353
IoStatementState &io, const DataEdit &edit, void *n, std::size_t bytes) {
5454
// Skip leading white space & zeroes
5555
common::optional<int> remaining{io.CueUpInput(edit)};
56-
auto start{io.GetConnectionState().positionInRecord};
56+
const ConnectionState &connection{io.GetConnectionState()};
57+
auto leftTabLimit{connection.leftTabLimit.value_or(0)};
58+
auto start{connection.positionInRecord - leftTabLimit};
5759
common::optional<char32_t> next{io.NextInField(remaining, edit)};
5860
if (next.value_or('?') == '0') {
5961
do {
60-
start = io.GetConnectionState().positionInRecord;
62+
start = connection.positionInRecord - leftTabLimit;
6163
next = io.NextInField(remaining, edit);
6264
} while (next && *next == '0');
6365
}
@@ -447,7 +449,9 @@ static RT_API_ATTRS ScannedRealInput ScanRealInput(
447449
}
448450
// In list-directed input, a bad exponent is not consumed.
449451
auto nextBeforeExponent{next};
450-
auto startExponent{io.GetConnectionState().positionInRecord};
452+
const ConnectionState &connection{io.GetConnectionState()};
453+
auto leftTabLimit{connection.leftTabLimit.value_or(0)};
454+
auto startExponent{connection.positionInRecord - leftTabLimit};
451455
bool hasGoodExponent{false};
452456
if (next) {
453457
if (isHexadecimal) {

flang-rt/lib/runtime/io-stmt.cpp

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,9 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
880880
edit.descriptor = DataEdit::ListDirectedImaginaryPart;
881881
}
882882
auto fastField{io.GetUpcomingFastAsciiField()};
883+
// Reaching EOF is okay when peeking at list-directed defined input;
884+
// pretend that there's an END= in that case.
885+
bool oldHasEnd{maxRepeat == 0 && !io.GetIoErrorHandler().SetHasEnd()};
883886
auto ch{io.GetNextNonBlank(byteCount, &fastField)};
884887
if (ch && *ch == comma && eatComma_) {
885888
// Consume comma & whitespace after previous item.
@@ -890,19 +893,23 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
890893
ch = io.GetNextNonBlank(byteCount, &fastField);
891894
}
892895
eatComma_ = true;
893-
if (!ch) {
894-
return common::nullopt;
896+
if (maxRepeat == 0 && !oldHasEnd) {
897+
io.GetIoErrorHandler().SetHasEnd(false);
895898
}
896-
if (*ch == '/') {
899+
if (!ch) { // EOF
900+
if (maxRepeat == 0) {
901+
return edit; // DataEdit::ListDirected for look-ahead
902+
} else {
903+
return common::nullopt;
904+
}
905+
} else if (*ch == '/') {
897906
hitSlash_ = true;
898907
edit.descriptor = DataEdit::ListDirectedNullValue;
899908
return edit;
900-
}
901-
if (*ch == comma) { // separator: null value
909+
} else if (*ch == comma) { // separator: null value
902910
edit.descriptor = DataEdit::ListDirectedNullValue;
903911
return edit;
904-
}
905-
if (imaginaryPart_) { // can't repeat components
912+
} else if (imaginaryPart_) { // can't repeat components
906913
return edit;
907914
}
908915
if (*ch >= '0' && *ch <= '9' && fastField.MightBeRepetitionCount()) {
@@ -1103,10 +1110,19 @@ ChildListIoStatementState<DIR>::ChildListIoStatementState(
11031110
: ChildIoStatementState<DIR>{child, sourceFile, sourceLine} {
11041111
#if !defined(RT_DEVICE_AVOID_RECURSION)
11051112
if constexpr (DIR == Direction::Input) {
1106-
if (auto *listInput{child.parent()
1113+
if (const auto *listInput{child.parent()
11071114
.get_if<ListDirectedStatementState<Direction::Input>>()}) {
11081115
this->set_eatComma(listInput->eatComma());
11091116
this->namelistGroup_ = listInput->namelistGroup();
1117+
if (auto *childListInput{child.parent()
1118+
.get_if<ChildListIoStatementState<Direction::Input>>()}) {
1119+
// Child list input whose parent is child list input: can advance
1120+
// if the parent can.
1121+
this->canAdvance_ = childListInput->CanAdvance();
1122+
} else {
1123+
// Child list input of top-level list input: can advance.
1124+
this->canAdvance_ = true;
1125+
}
11101126
}
11111127
}
11121128
#else
@@ -1117,12 +1133,7 @@ ChildListIoStatementState<DIR>::ChildListIoStatementState(
11171133
template <Direction DIR>
11181134
bool ChildListIoStatementState<DIR>::AdvanceRecord(int n) {
11191135
#if !defined(RT_DEVICE_AVOID_RECURSION)
1120-
// Allow child NAMELIST input to advance
1121-
if (DIR == Direction::Input && this->mutableModes().inNamelist) {
1122-
return this->child().parent().AdvanceRecord(n);
1123-
} else {
1124-
return false;
1125-
}
1136+
return this->CanAdvance() && this->child().parent().AdvanceRecord(n);
11261137
#else
11271138
this->ReportUnsupportedChildIo();
11281139
#endif

flang/docs/Extensions.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,17 @@ print *, [(j,j=1,10)]
928928
and the portable interpretation across the most common Fortran
929929
compilers.
930930

931+
* `NAMELIST` child input statements are allowed to advance to further
932+
input records.
933+
Further, advancement is allowed when the parent input statement is
934+
a non-child (top level) list-directed input statement, or, recursively,
935+
an intermediate child list-directed input statement that can advance.
936+
This means that non-`NAMELIST` list-directed child input statements are
937+
not allowed to advance when they have an ancestor formatted input statement
938+
that is not list-directed and there is no intervening `NAMELIST`.
939+
This design allows format-driven input with `DT` editing to retain
940+
control over advancement in child input, while otherwise allowing it.
941+
931942
## De Facto Standard Features
932943

933944
* `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the

0 commit comments

Comments
 (0)