Skip to content

Commit 2036011

Browse files
klauslervdonaldson
authored andcommitted
[flang] Correct INQUIRE(POSITION= & PAD=)
INQUIRE(POSITION=)'s results need to reflect the POSITION= specifier used for the OPEN statement until the unit has been repositioned. Preserve the POSITION= from OPEN and used it for INQUIRE(POSITION=) until is becomes obsolete. INQUIRE(PAD=) is implemented here in the case of an unconnected unit with Fortran 2018 semantics; i.e., "UNDEFINED", rather than Fortran 90's "YES"/"NO" (see 4.3.6 para 2). Apparent failures with F'90-only tests will persist with INQUIRE(PAD=); these discrepancies don't seem to warrant an option or environment variable. To make the implementation of INQUIRE more closely match the language in the standard, rename IsOpen() to IsConnected(), and use it explicitly for the various INQUIRE specifiers. Differential Revision: https://reviews.llvm.org/D114755
1 parent d8b588b commit 2036011

File tree

6 files changed

+109
-57
lines changed

6 files changed

+109
-57
lines changed

flang/runtime/connection.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ enum class Access { Sequential, Direct, Stream };
2525
inline bool IsRecordFile(Access a) { return a != Access::Stream; }
2626

2727
// These characteristics of a connection are immutable after being
28-
// established in an OPEN statement.
28+
// established in an OPEN statement, except for recordLength,
29+
// which is immutable only when isFixedRecordLength is true.
2930
struct ConnectionAttributes {
3031
Access access{Access::Sequential}; // ACCESS='SEQUENTIAL', 'DIRECT', 'STREAM'
3132
std::optional<bool> isUnformatted; // FORM='UNFORMATTED' if true

flang/runtime/file.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ void OpenFile::Open(OpenStatus status, std::optional<Action> action,
149149
knownSize_ = 0;
150150
mayPosition_ = true;
151151
}
152+
openPosition_ = position; // for INQUIRE(POSITION=)
152153
}
153154

154155
void OpenFile::Predefine(int fd) {
@@ -208,7 +209,7 @@ std::size_t OpenFile::Read(FileOffset at, char *buffer, std::size_t minBytes,
208209
break;
209210
}
210211
} else {
211-
position_ += chunk;
212+
SetPosition(position_ + chunk);
212213
got += chunk;
213214
}
214215
}
@@ -228,7 +229,7 @@ std::size_t OpenFile::Write(FileOffset at, const char *buffer,
228229
while (put < bytes) {
229230
auto chunk{::write(fd_, buffer + put, bytes - put)};
230231
if (chunk >= 0) {
231-
position_ += chunk;
232+
SetPosition(position_ + chunk);
232233
put += chunk;
233234
} else {
234235
auto err{errno};
@@ -351,6 +352,20 @@ void OpenFile::WaitAll(IoErrorHandler &handler) {
351352
}
352353
}
353354

355+
Position OpenFile::InquirePosition() const {
356+
if (openPosition_) { // from OPEN statement
357+
return *openPosition_;
358+
} else { // unit has been repositioned since opening
359+
if (position_ == knownSize_.value_or(position_ + 1)) {
360+
return Position::Append;
361+
} else if (position_ == 0 && mayPosition_) {
362+
return Position::Rewind;
363+
} else {
364+
return Position::AsIs; // processor-dependent & no common behavior
365+
}
366+
}
367+
}
368+
354369
void OpenFile::CheckOpen(const Terminator &terminator) {
355370
RUNTIME_CHECK(terminator, fd_ >= 0);
356371
}
@@ -359,7 +374,7 @@ bool OpenFile::Seek(FileOffset at, IoErrorHandler &handler) {
359374
if (at == position_) {
360375
return true;
361376
} else if (RawSeek(at)) {
362-
position_ = at;
377+
SetPosition(at);
363378
return true;
364379
} else {
365380
handler.SignalErrno();

flang/runtime/file.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class OpenFile {
3939
bool isTerminal() const { return isTerminal_; }
4040
std::optional<FileOffset> knownSize() const { return knownSize_; }
4141

42-
bool IsOpen() const { return fd_ >= 0; }
42+
bool IsConnected() const { return fd_ >= 0; }
4343
void Open(OpenStatus, std::optional<Action>, Position, IoErrorHandler &);
4444
void Predefine(int fd);
4545
void Close(CloseStatus, IoErrorHandler &);
@@ -66,6 +66,9 @@ class OpenFile {
6666
void Wait(int id, IoErrorHandler &);
6767
void WaitAll(IoErrorHandler &);
6868

69+
// INQUIRE(POSITION=)
70+
Position InquirePosition() const;
71+
6972
private:
7073
struct Pending {
7174
int id;
@@ -78,6 +81,10 @@ class OpenFile {
7881
bool RawSeek(FileOffset);
7982
bool RawSeekToEnd();
8083
int PendingResult(const Terminator &, int);
84+
void SetPosition(FileOffset pos) {
85+
position_ = pos;
86+
openPosition_.reset();
87+
}
8188

8289
int fd_{-1};
8390
OwningPtr<char> path_;
@@ -86,6 +93,7 @@ class OpenFile {
8693
bool mayWrite_{false};
8794
bool mayPosition_{false};
8895
bool mayAsynchronous_{false};
96+
std::optional<Position> openPosition_; // from Open(); reset after positioning
8997
FileOffset position_{0};
9098
std::optional<FileOffset> knownSize_;
9199
bool isTerminal_{false};

flang/runtime/io-stmt.cpp

Lines changed: 77 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -824,26 +824,35 @@ bool InquireUnitState::Inquire(
824824
const char *str{nullptr};
825825
switch (inquiry) {
826826
case HashInquiryKeyword("ACCESS"):
827-
switch (unit().access) {
828-
case Access::Sequential:
829-
str = "SEQUENTIAL";
830-
break;
831-
case Access::Direct:
832-
str = "DIRECT";
833-
break;
834-
case Access::Stream:
835-
str = "STREAM";
836-
break;
827+
if (!unit().IsConnected()) {
828+
str = "UNDEFINED";
829+
} else {
830+
switch (unit().access) {
831+
case Access::Sequential:
832+
str = "SEQUENTIAL";
833+
break;
834+
case Access::Direct:
835+
str = "DIRECT";
836+
break;
837+
case Access::Stream:
838+
str = "STREAM";
839+
break;
840+
}
837841
}
838842
break;
839843
case HashInquiryKeyword("ACTION"):
840-
str = unit().mayWrite() ? unit().mayRead() ? "READWRITE" : "WRITE" : "READ";
844+
str = !unit().IsConnected() ? "UNDEFINED"
845+
: unit().mayWrite() ? unit().mayRead() ? "READWRITE" : "WRITE"
846+
: "READ";
841847
break;
842848
case HashInquiryKeyword("ASYNCHRONOUS"):
843-
str = unit().mayAsynchronous() ? "YES" : "NO";
849+
str = !unit().IsConnected() ? "UNDEFINED"
850+
: unit().mayAsynchronous() ? "YES"
851+
: "NO";
844852
break;
845853
case HashInquiryKeyword("BLANK"):
846-
str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
854+
str = !unit().IsConnected() || unit().isUnformatted.value_or(true)
855+
? "UNDEFINED"
847856
: unit().modes.editingFlags & blankZero ? "ZERO"
848857
: "NULL";
849858
break;
@@ -854,12 +863,13 @@ bool InquireUnitState::Inquire(
854863
str = unit().swapEndianness() ? "SWAP" : "NATIVE";
855864
break;
856865
case HashInquiryKeyword("DECIMAL"):
857-
str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
866+
str = !unit().IsConnected() || unit().isUnformatted.value_or(true)
867+
? "UNDEFINED"
858868
: unit().modes.editingFlags & decimalComma ? "COMMA"
859869
: "POINT";
860870
break;
861871
case HashInquiryKeyword("DELIM"):
862-
if (unit().isUnformatted.value_or(true)) {
872+
if (!unit().IsConnected() || unit().isUnformatted.value_or(true)) {
863873
str = "UNDEFINED";
864874
} else {
865875
switch (unit().modes.delim) {
@@ -876,23 +886,26 @@ bool InquireUnitState::Inquire(
876886
}
877887
break;
878888
case HashInquiryKeyword("DIRECT"):
879-
str = unit().access == Access::Direct ||
889+
str = !unit().IsConnected() ? "UNKNOWN"
890+
: unit().access == Access::Direct ||
880891
(unit().mayPosition() && unit().isFixedRecordLength)
881892
? "YES"
882893
: "NO";
883894
break;
884895
case HashInquiryKeyword("ENCODING"):
885-
str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
896+
str = !unit().IsConnected() ? "UNKNOWN"
897+
: unit().isUnformatted.value_or(true) ? "UNDEFINED"
886898
: unit().isUTF8 ? "UTF-8"
887899
: "ASCII";
888900
break;
889901
case HashInquiryKeyword("FORM"):
890-
str = !unit().isUnformatted ? "UNDEFINED"
891-
: *unit().isUnformatted ? "UNFORMATTED"
892-
: "FORMATTED";
902+
str = !unit().IsConnected() || !unit().isUnformatted ? "UNDEFINED"
903+
: *unit().isUnformatted ? "UNFORMATTED"
904+
: "FORMATTED";
893905
break;
894906
case HashInquiryKeyword("FORMATTED"):
895-
str = !unit().isUnformatted ? "UNKNOWN"
907+
str = !unit().IsConnected() ? "UNDEFINED"
908+
: !unit().isUnformatted ? "UNKNOWN"
896909
: *unit().isUnformatted ? "NO"
897910
: "YES";
898911
break;
@@ -903,33 +916,38 @@ bool InquireUnitState::Inquire(
903916
}
904917
break;
905918
case HashInquiryKeyword("PAD"):
906-
str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
907-
: unit().modes.pad ? "YES"
908-
: "NO";
919+
str = !unit().IsConnected() || unit().isUnformatted.value_or(true)
920+
? "UNDEFINED"
921+
: unit().modes.pad ? "YES"
922+
: "NO";
909923
break;
910924
case HashInquiryKeyword("POSITION"):
911-
if (unit().access == Access::Direct) {
925+
if (!unit().IsConnected() || unit().access == Access::Direct) {
912926
str = "UNDEFINED";
913927
} else {
914-
auto size{unit().knownSize()};
915-
auto pos{unit().position()};
916-
if (pos == size.value_or(pos + 1)) {
917-
str = "APPEND";
918-
} else if (pos == 0 && unit().mayPosition()) {
928+
switch (unit().InquirePosition()) {
929+
case Position::Rewind:
919930
str = "REWIND";
920-
} else {
921-
str = "ASIS"; // processor-dependent & no common behavior
931+
break;
932+
case Position::Append:
933+
str = "APPEND";
934+
break;
935+
case Position::AsIs:
936+
str = "ASIS";
937+
break;
922938
}
923939
}
924940
break;
925941
case HashInquiryKeyword("READ"):
926-
str = unit().mayRead() ? "YES" : "NO";
942+
str = !unit().IsConnected() ? "UNDEFINED" : unit().mayRead() ? "YES" : "NO";
927943
break;
928944
case HashInquiryKeyword("READWRITE"):
929-
str = unit().mayRead() && unit().mayWrite() ? "YES" : "NO";
945+
str = !unit().IsConnected() ? "UNDEFINED"
946+
: unit().mayRead() && unit().mayWrite() ? "YES"
947+
: "NO";
930948
break;
931949
case HashInquiryKeyword("ROUND"):
932-
if (unit().isUnformatted.value_or(true)) {
950+
if (!unit().IsConnected() || unit().isUnformatted.value_or(true)) {
933951
str = "UNDEFINED";
934952
} else {
935953
switch (unit().modes.round) {
@@ -954,23 +972,28 @@ bool InquireUnitState::Inquire(
954972
case HashInquiryKeyword("SEQUENTIAL"):
955973
// "NO" for Direct, since Sequential would not work if
956974
// the unit were reopened without RECL=.
957-
str = unit().access == Access::Sequential ? "YES" : "NO";
975+
str = !unit().IsConnected() ? "UNKNOWN"
976+
: unit().access == Access::Sequential ? "YES"
977+
: "NO";
958978
break;
959979
case HashInquiryKeyword("SIGN"):
960-
str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
980+
str = !unit().IsConnected() || unit().isUnformatted.value_or(true)
981+
? "UNDEFINED"
961982
: unit().modes.editingFlags & signPlus ? "PLUS"
962983
: "SUPPRESS";
963984
break;
964985
case HashInquiryKeyword("STREAM"):
965-
str = unit().access == Access::Stream ? "YES" : "NO";
966-
break;
967-
case HashInquiryKeyword("WRITE"):
968-
str = unit().mayWrite() ? "YES" : "NO";
986+
str = !unit().IsConnected() ? "UNKNOWN"
987+
: unit().access == Access::Stream ? "YES"
988+
: "NO";
969989
break;
970990
case HashInquiryKeyword("UNFORMATTED"):
971-
str = !unit().isUnformatted ? "UNKNOWN"
972-
: *unit().isUnformatted ? "YES"
973-
: "NO";
991+
str = !unit().IsConnected() || !unit().isUnformatted ? "UNKNOWN"
992+
: *unit().isUnformatted ? "YES"
993+
: "NO";
994+
break;
995+
case HashInquiryKeyword("WRITE"):
996+
str = !unit().IsConnected() ? "UNKNOWN" : unit().mayWrite() ? "YES" : "NO";
974997
break;
975998
}
976999
if (str) {
@@ -991,7 +1014,7 @@ bool InquireUnitState::Inquire(InquiryKeywordHash inquiry, bool &result) {
9911014
result = unit().path() != nullptr;
9921015
return true;
9931016
case HashInquiryKeyword("OPENED"):
994-
result = true;
1017+
result = unit().IsConnected();
9951018
return true;
9961019
case HashInquiryKeyword("PENDING"):
9971020
result = false; // asynchronous I/O is not implemented
@@ -1023,13 +1046,15 @@ bool InquireUnitState::Inquire(
10231046
}
10241047
return true;
10251048
case HashInquiryKeyword("NUMBER"):
1026-
result = unit().unitNumber();
1049+
result = unit().IsConnected() ? unit().unitNumber() : -1;
10271050
return true;
10281051
case HashInquiryKeyword("POS"):
10291052
result = unit().position();
10301053
return true;
10311054
case HashInquiryKeyword("RECL"):
1032-
if (unit().access == Access::Stream) {
1055+
if (!unit().IsConnected()) {
1056+
result = -1;
1057+
} else if (unit().access == Access::Stream) {
10331058
result = -2;
10341059
} else if (unit().isFixedRecordLength && unit().recordLength) {
10351060
result = *unit().recordLength;
@@ -1038,10 +1063,11 @@ bool InquireUnitState::Inquire(
10381063
}
10391064
return true;
10401065
case HashInquiryKeyword("SIZE"):
1041-
if (auto size{unit().knownSize()}) {
1042-
result = *size;
1043-
} else {
1044-
result = -1;
1066+
result = -1;
1067+
if (unit().IsConnected()) {
1068+
if (auto size{unit().knownSize()}) {
1069+
result = *size;
1070+
}
10451071
}
10461072
return true;
10471073
default:

flang/runtime/unit.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ void ExternalFileUnit::OpenUnit(std::optional<OpenStatus> status,
107107
swapEndianness_ = convert == Convert::Swap ||
108108
(convert == Convert::LittleEndian && !isHostLittleEndian) ||
109109
(convert == Convert::BigEndian && isHostLittleEndian);
110-
if (IsOpen()) {
110+
if (IsConnected()) {
111111
bool isSamePath{newPath.get() && path() && pathLength() == newPathLength &&
112112
std::memcmp(path(), newPath.get(), newPathLength) == 0};
113113
if (status && *status != OpenStatus::Old && isSamePath) {

flang/runtime/unit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class ExternalFileUnit : public ConnectionState,
3535
public FileFrame<ExternalFileUnit> {
3636
public:
3737
explicit ExternalFileUnit(int unitNumber) : unitNumber_{unitNumber} {}
38+
~ExternalFileUnit() {}
39+
3840
int unitNumber() const { return unitNumber_; }
3941
bool swapEndianness() const { return swapEndianness_; }
4042
bool createdForInternalChildIo() const { return createdForInternalChildIo_; }

0 commit comments

Comments
 (0)