Skip to content

Commit c963757

Browse files
committed
[flang] Implement nonstandard OPEN statement CARRIAGECONTROL specifier
Differential Revision: https://reviews.llvm.org/D87052
1 parent 5b4744b commit c963757

File tree

13 files changed

+98
-24
lines changed

13 files changed

+98
-24
lines changed

flang/docs/Extensions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Extensions, deletions, and legacy features supported by default
5656
* `NAME=` as synonym for `FILE=`
5757
* Data edit descriptors without width or other details
5858
* `D` lines in fixed form as comments or debug code
59+
* `CARRIAGECONTROL=` on the OPEN and INQUIRE statements
5960
* `CONVERT=` on the OPEN and INQUIRE statements
6061
* `DISPOSE=` on the OPEN and INQUIRE statements
6162
* Leading semicolons are ignored before any statement that

flang/docs/f2018-grammar.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,8 @@ R1205 connect-spec ->
577577
POSITION = scalar-default-char-expr | RECL = scalar-int-expr |
578578
ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
579579
STATUS = scalar-default-char-expr
580-
@ | CONVERT = scalar-default-char-expr
580+
@ | CARRIAGECONTROL = scalar-default-char-expr
581+
| CONVERT = scalar-default-char-expr
581582
| DISPOSE = scalar-default-char-expr
582583
R1206 file-name-expr -> scalar-default-char-expr
583584
R1207 iomsg-variable -> scalar-default-char-variable
@@ -657,7 +658,8 @@ R1231 inquire-spec ->
657658
STREAM = scalar-default-char-variable |
658659
STATUS = scalar-default-char-variable |
659660
WRITE = scalar-default-char-variable
660-
@ | CONVERT = scalar-default-char-expr
661+
@ | CARRIAGECONTROL = scalar-default-char-expr
662+
| CONVERT = scalar-default-char-expr
661663
| DISPOSE = scalar-default-char-expr
662664

663665
R1301 format-stmt -> FORMAT format-specification

flang/include/flang/Common/Fortran-features.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
2222
DoubleComplex, Byte, StarKind, QuadPrecision, SlashInitialization,
2323
TripletInArrayConstructor, MissingColons, SignedComplexLiteral,
2424
OldStyleParameter, ComplexConstructor, PercentLOC, SignedPrimary, FileName,
25-
Convert, Dispose, IOListLeadingComma, AbbreviatedEditDescriptor,
26-
ProgramParentheses, PercentRefAndVal, OmitFunctionDummies, CrayPointer,
27-
Hollerith, ArithmeticIF, Assign, AssignedGOTO, Pause, OpenACC, OpenMP,
28-
CruftAfterAmpersand, ClassicCComments, AdditionalFormats, BigIntLiterals,
29-
RealDoControls, EquivalenceNumericWithCharacter, AdditionalIntrinsics,
30-
AnonymousParents, OldLabelDoEndStatements, LogicalIntegerAssignment,
31-
EmptySourceFile, ProgramReturn, ImplicitNoneTypeNever,
32-
ImplicitNoneTypeAlways)
25+
Carriagecontrol, Convert, Dispose, IOListLeadingComma,
26+
AbbreviatedEditDescriptor, ProgramParentheses, PercentRefAndVal,
27+
OmitFunctionDummies, CrayPointer, Hollerith, ArithmeticIF, Assign,
28+
AssignedGOTO, Pause, OpenACC, OpenMP, CruftAfterAmpersand, ClassicCComments,
29+
AdditionalFormats, BigIntLiterals, RealDoControls,
30+
EquivalenceNumericWithCharacter, AdditionalIntrinsics, AnonymousParents,
31+
OldLabelDoEndStatements, LogicalIntegerAssignment, EmptySourceFile,
32+
ProgramReturn, ImplicitNoneTypeNever, ImplicitNoneTypeAlways)
3333

3434
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
3535

flang/include/flang/Common/Fortran.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ ENUM_CLASS(IoSpecKind, Access, Action, Advance, Asynchronous, Blank, Decimal,
5252
Id, Iomsg, Iostat, Name, Named, Newunit, Nextrec, Nml, Number, Opened, Pad,
5353
Pending, Pos, Position, Read, Readwrite, Rec, Recl, Round, Sequential, Sign,
5454
Size, Status, Stream, Unformatted, Unit, Write,
55+
Carriagecontrol, // nonstandard
5556
Convert, // nonstandard
5657
Dispose, // nonstandard
5758
)

flang/include/flang/Parser/parse-tree.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2549,7 +2549,8 @@ using FileNameExpr = ScalarDefaultCharExpr;
25492549
// POSITION = scalar-default-char-expr | RECL = scalar-int-expr |
25502550
// ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
25512551
// STATUS = scalar-default-char-expr
2552-
// @ | CONVERT = scalar-default-char-variable
2552+
// @ | CARRIAGECONTROL = scalar-default-char-variable
2553+
// | CONVERT = scalar-default-char-variable
25532554
// | DISPOSE = scalar-default-char-variable
25542555
WRAPPER_CLASS(StatusExpr, ScalarDefaultCharExpr);
25552556
WRAPPER_CLASS(ErrLabel, Label);
@@ -2559,7 +2560,7 @@ struct ConnectSpec {
25592560
struct CharExpr {
25602561
ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim,
25612562
Encoding, Form, Pad, Position, Round, Sign,
2562-
/* extensions: */ Convert, Dispose)
2563+
/* extensions: */ Carriagecontrol, Convert, Dispose)
25632564
TUPLE_CLASS_BOILERPLATE(CharExpr);
25642565
std::tuple<Kind, ScalarDefaultCharExpr> t;
25652566
};
@@ -2767,15 +2768,16 @@ WRAPPER_CLASS(FlushStmt, std::list<PositionOrFlushSpec>);
27672768
// STATUS = scalar-default-char-variable |
27682769
// UNFORMATTED = scalar-default-char-variable |
27692770
// WRITE = scalar-default-char-variable
2770-
// @ | CONVERT = scalar-default-char-variable
2771+
// @ | CARRIAGECONTROL = scalar-default-char-variable
2772+
// | CONVERT = scalar-default-char-variable
27712773
// | DISPOSE = scalar-default-char-variable
27722774
struct InquireSpec {
27732775
UNION_CLASS_BOILERPLATE(InquireSpec);
27742776
struct CharVar {
27752777
ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim,
27762778
Direct, Encoding, Form, Formatted, Iomsg, Name, Pad, Position, Read,
27772779
Readwrite, Round, Sequential, Sign, Stream, Status, Unformatted, Write,
2778-
/* extensions: */ Convert, Dispose)
2780+
/* extensions: */ Carriagecontrol, Convert, Dispose)
27792781
TUPLE_CLASS_BOILERPLATE(CharVar);
27802782
std::tuple<Kind, ScalarDefaultCharVariable> t;
27812783
};

flang/lib/Lower/IO.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ static constexpr std::tuple<
6060
mkIOKey(OutputComplex64), mkIOKey(OutputComplex32), mkIOKey(OutputAscii),
6161
mkIOKey(InputAscii), mkIOKey(OutputLogical), mkIOKey(InputLogical),
6262
mkIOKey(SetAccess), mkIOKey(SetAction), mkIOKey(SetAsynchronous),
63-
mkIOKey(SetEncoding), mkIOKey(SetForm), mkIOKey(SetPosition),
64-
mkIOKey(SetRecl), mkIOKey(SetStatus), mkIOKey(SetFile), mkIOKey(GetNewUnit),
65-
mkIOKey(GetSize), mkIOKey(GetIoLength), mkIOKey(GetIoMsg),
66-
mkIOKey(InquireCharacter), mkIOKey(InquireLogical),
67-
mkIOKey(InquirePendingId), mkIOKey(InquireInteger64),
68-
mkIOKey(EndIoStatement)>
63+
mkIOKey(SetCarriagecontrol), mkIOKey(SetEncoding), mkIOKey(SetForm),
64+
mkIOKey(SetPosition), mkIOKey(SetRecl), mkIOKey(SetStatus),
65+
mkIOKey(SetFile), mkIOKey(GetNewUnit), mkIOKey(GetSize),
66+
mkIOKey(GetIoLength), mkIOKey(GetIoMsg), mkIOKey(InquireCharacter),
67+
mkIOKey(InquireLogical), mkIOKey(InquirePendingId),
68+
mkIOKey(InquireInteger64), mkIOKey(EndIoStatement)>
6969
newIOTable;
7070
} // namespace Fortran::lower
7171

@@ -599,6 +599,9 @@ mlir::Value genIOOption<Fortran::parser::ConnectSpec::CharExpr>(
599599
case Fortran::parser::ConnectSpec::CharExpr::Kind::Sign:
600600
ioFunc = getIORuntimeFunc<mkIOKey(SetSign)>(loc, builder);
601601
break;
602+
case Fortran::parser::ConnectSpec::CharExpr::Kind::Carriagecontrol:
603+
ioFunc = getIORuntimeFunc<mkIOKey(SetCarriagecontrol)>(loc, builder);
604+
break;
602605
case Fortran::parser::ConnectSpec::CharExpr::Kind::Convert:
603606
llvm_unreachable("CONVERT not part of the runtime::io interface");
604607
case Fortran::parser::ConnectSpec::CharExpr::Kind::Dispose:

flang/lib/Parser/io-parsers.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ constexpr auto fileNameExpr{scalarDefaultCharExpr};
5454
// POSITION = scalar-default-char-expr | RECL = scalar-int-expr |
5555
// ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr |
5656
// STATUS = scalar-default-char-expr
57-
// @ | CONVERT = scalar-default-char-variable
58-
// @ | DISPOSE = scalar-default-char-variable
57+
// @ | CARRIAGECONTROL = scalar-default-char-variable
58+
// | CONVERT = scalar-default-char-variable
59+
// | DISPOSE = scalar-default-char-variable
5960
constexpr auto statusExpr{construct<StatusExpr>(scalarDefaultCharExpr)};
6061
constexpr auto errLabel{construct<ErrLabel>(label)};
6162

@@ -107,6 +108,10 @@ TYPE_PARSER(first(construct<ConnectSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
107108
"SIGN =" >> pure(ConnectSpec::CharExpr::Kind::Sign),
108109
scalarDefaultCharExpr)),
109110
construct<ConnectSpec>("STATUS =" >> statusExpr),
111+
extension<LanguageFeature::Carriagecontrol>(construct<ConnectSpec>(
112+
construct<ConnectSpec::CharExpr>("CARRIAGECONTROL =" >>
113+
pure(ConnectSpec::CharExpr::Kind::Carriagecontrol),
114+
scalarDefaultCharExpr))),
110115
extension<LanguageFeature::Convert>(
111116
construct<ConnectSpec>(construct<ConnectSpec::CharExpr>(
112117
"CONVERT =" >> pure(ConnectSpec::CharExpr::Kind::Convert),
@@ -357,7 +362,8 @@ TYPE_CONTEXT_PARSER("FLUSH statement"_en_US,
357362
// STREAM = scalar-default-char-variable |
358363
// STATUS = scalar-default-char-variable |
359364
// WRITE = scalar-default-char-variable
360-
// @ | CONVERT = scalar-default-char-variable
365+
// @ | CARRIAGECONTROL = scalar-default-char-variable
366+
// | CONVERT = scalar-default-char-variable
361367
// | DISPOSE = scalar-default-char-variable
362368
TYPE_PARSER(first(construct<InquireSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
363369
construct<InquireSpec>("FILE =" >> fileNameExpr),
@@ -475,6 +481,11 @@ TYPE_PARSER(first(construct<InquireSpec>(maybe("UNIT ="_tok) >> fileUnitNumber),
475481
construct<InquireSpec>("WRITE =" >>
476482
construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Write),
477483
scalarDefaultCharVariable)),
484+
extension<LanguageFeature::Carriagecontrol>(
485+
construct<InquireSpec>("CARRIAGECONTROL =" >>
486+
construct<InquireSpec::CharVar>(
487+
pure(InquireSpec::CharVar::Kind::Carriagecontrol),
488+
scalarDefaultCharVariable))),
478489
extension<LanguageFeature::Convert>(construct<InquireSpec>(
479490
"CONVERT =" >> construct<InquireSpec::CharVar>(
480491
pure(InquireSpec::CharVar::Kind::Convert),

flang/lib/Semantics/check-io.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ void IoChecker::Enter(const parser::ConnectSpec::CharExpr &spec) {
135135
case ParseKind::Sign:
136136
specKind = IoSpecKind::Sign;
137137
break;
138+
case ParseKind::Carriagecontrol:
139+
specKind = IoSpecKind::Carriagecontrol;
140+
break;
138141
case ParseKind::Convert:
139142
specKind = IoSpecKind::Convert;
140143
break;
@@ -152,6 +155,13 @@ void IoChecker::Enter(const parser::ConnectSpec::CharExpr &spec) {
152155
flags_.set(Flag::AccessStream, s == "STREAM");
153156
}
154157
CheckStringValue(specKind, *charConst, parser::FindSourceLocation(spec));
158+
if (specKind == IoSpecKind::Carriagecontrol &&
159+
(s == "FORTRAN" || s == "NONE")) {
160+
context_.Say(parser::FindSourceLocation(spec),
161+
"Unimplemented %s value '%s'"_err_en_US,
162+
parser::ToUpperCaseLetters(common::EnumToString(specKind)),
163+
*charConst);
164+
}
155165
}
156166
}
157167

@@ -378,6 +388,9 @@ void IoChecker::Enter(const parser::InquireSpec::CharVar &spec) {
378388
case ParseKind::Write:
379389
specKind = IoSpecKind::Write;
380390
break;
391+
case ParseKind::Carriagecontrol:
392+
specKind = IoSpecKind::Carriagecontrol;
393+
break;
381394
case ParseKind::Convert:
382395
specKind = IoSpecKind::Convert;
383396
break;
@@ -821,6 +834,7 @@ void IoChecker::CheckStringValue(IoSpecKind specKind, const std::string &value,
821834
{IoSpecKind::Status,
822835
// Open values; Close values are {"DELETE", "KEEP"}.
823836
{"NEW", "OLD", "REPLACE", "SCRATCH", "UNKNOWN"}},
837+
{IoSpecKind::Carriagecontrol, {"LIST", "FORTRAN", "NONE"}},
824838
{IoSpecKind::Convert, {"BIG_ENDIAN", "LITTLE_ENDIAN", "NATIVE"}},
825839
{IoSpecKind::Dispose, {"DELETE", "KEEP"}},
826840
};

flang/runtime/io-api.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,31 @@ bool IONAME(SetAsynchronous)(
655655
}
656656
}
657657

658+
bool IONAME(SetCarriagecontrol)(
659+
Cookie cookie, const char *keyword, std::size_t length) {
660+
IoStatementState &io{*cookie};
661+
auto *open{io.get_if<OpenStatementState>()};
662+
if (!open) {
663+
io.GetIoErrorHandler().Crash(
664+
"SetCarriageControl() called when not in an OPEN statement");
665+
}
666+
static const char *keywords[]{"LIST", "FORTRAN", "NONE", nullptr};
667+
switch (IdentifyValue(keyword, length, keywords)) {
668+
case 0:
669+
return true;
670+
case 1:
671+
case 2:
672+
open->SignalError(IostatErrorInKeyword,
673+
"Unimplemented CARRIAGECONTROL='%.*s'", static_cast<int>(length),
674+
keyword);
675+
return false;
676+
default:
677+
open->SignalError(IostatErrorInKeyword, "Invalid CARRIAGECONTROL='%.*s'",
678+
static_cast<int>(length), keyword);
679+
return false;
680+
}
681+
}
682+
658683
bool IONAME(SetConvert)(
659684
Cookie cookie, const char *keyword, std::size_t length) {
660685
IoStatementState &io{*cookie};
@@ -708,7 +733,7 @@ bool IONAME(SetForm)(Cookie cookie, const char *keyword, std::size_t length) {
708733
auto *open{io.get_if<OpenStatementState>()};
709734
if (!open) {
710735
io.GetIoErrorHandler().Crash(
711-
"SetEncoding() called when not in an OPEN statement");
736+
"SetForm() called when not in an OPEN statement");
712737
}
713738
static const char *keywords[]{"FORMATTED", "UNFORMATTED", nullptr};
714739
switch (IdentifyValue(keyword, length, keywords)) {

flang/runtime/io-api.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ bool IONAME(SetAccess)(Cookie, const char *, std::size_t);
260260
bool IONAME(SetAction)(Cookie, const char *, std::size_t);
261261
// ASYNCHRONOUS=YES, NO
262262
bool IONAME(SetAsynchronous)(Cookie, const char *, std::size_t);
263+
// CARRIAGECONTROL=LIST, FORTRAN, NONE
264+
bool IONAME(SetCarriagecontrol)(Cookie, const char *, std::size_t);
263265
// CONVERT=NATIVE, LITTLE_ENDIAN, BIG_ENDIAN, or SWAP
264266
bool IONAME(SetConvert)(Cookie, const char *, std::size_t);
265267
// ENCODING=UTF-8, DEFAULT

0 commit comments

Comments
 (0)