Skip to content

Commit 0cca990

Browse files
committed
IoUnit allows arbitrary expression
1 parent 8260528 commit 0cca990

File tree

7 files changed

+68
-6
lines changed

7 files changed

+68
-6
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2642,7 +2642,7 @@ WRAPPER_CLASS(FileUnitNumber, ScalarIntExpr);
26422642
// symbols are known.
26432643
struct IoUnit {
26442644
UNION_CLASS_BOILERPLATE(IoUnit);
2645-
std::variant<Variable, FileUnitNumber, Star> u;
2645+
std::variant<Variable, common::Indirection<Expr>, Star> u;
26462646
};
26472647

26482648
// R1206 file-name-expr -> scalar-default-char-expr

flang/lib/Lower/IO.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1841,7 +1841,9 @@ static mlir::Value genIOUnit(Fortran::lower::AbstractConverter &converter,
18411841
int defaultUnitNumber) {
18421842
auto &builder = converter.getFirOpBuilder();
18431843
if (iounit)
1844-
if (auto *e = std::get_if<Fortran::parser::FileUnitNumber>(&iounit->u))
1844+
if (auto *e =
1845+
std::get_if<Fortran::common::Indirection<Fortran::parser::Expr>>(
1846+
&iounit->u))
18451847
return genIOUnitNumber(converter, loc, Fortran::semantics::GetExpr(*e),
18461848
ty, csi, stmtCtx);
18471849
return builder.create<mlir::arith::ConstantOp>(

flang/lib/Parser/io-parsers.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ namespace Fortran::parser {
2323
// R905 char-variable -> variable
2424
// "char-variable" is attempted first since it's not type constrained but
2525
// syntactically ambiguous with "file-unit-number", which is constrained.
26+
// Note, "file-unit-number" is replaced by "expr" to allow for better
27+
// error messages.
2628
TYPE_PARSER(construct<IoUnit>(variable / lookAhead(space / ",);\n"_ch)) ||
27-
construct<IoUnit>(fileUnitNumber) || construct<IoUnit>(star))
29+
construct<IoUnit>(
30+
indirect(expr) / (lookAhead(space >> ",)"_ch) || atEndOfStmt)) ||
31+
construct<IoUnit>(star))
2832

2933
// R1202 file-unit-number -> scalar-int-expr
3034
TYPE_PARSER(construct<FileUnitNumber>(

flang/lib/Semantics/check-io.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
#include "check-io.h"
1010
#include "definable.h"
1111
#include "flang/Common/format.h"
12+
#include "flang/Common/indirection.h"
1213
#include "flang/Evaluate/tools.h"
14+
#include "flang/Parser/characters.h"
1315
#include "flang/Parser/tools.h"
1416
#include "flang/Semantics/expression.h"
1517
#include "flang/Semantics/tools.h"
@@ -576,8 +578,9 @@ void IoChecker::Enter(const parser::IoUnit &spec) {
576578
std::move(mutableVar.u))};
577579
newExpr.source = source;
578580
newExpr.typedExpr = std::move(typedExpr);
579-
mutableSpec.u = parser::FileUnitNumber{
580-
parser::ScalarIntExpr{parser::IntExpr{std::move(newExpr)}}};
581+
mutableSpec.u = common::Indirection<parser::Expr>{std::move(newExpr)};
582+
SetSpecifier(IoSpecKind::Unit);
583+
flags_.set(Flag::NumberUnit);
581584
} else if (!dyType || dyType->category() != TypeCategory::Character) {
582585
SetSpecifier(IoSpecKind::Unit);
583586
context_.Say(parser::FindSourceLocation(*var),
@@ -598,6 +601,26 @@ void IoChecker::Enter(const parser::IoUnit &spec) {
598601
} else if (std::get_if<parser::Star>(&spec.u)) {
599602
SetSpecifier(IoSpecKind::Unit);
600603
flags_.set(Flag::StarUnit);
604+
} else if (const common::Indirection<parser::Expr> *pexpr{
605+
std::get_if<common::Indirection<parser::Expr>>(&spec.u)}) {
606+
const auto *expr{GetExpr(context_, *pexpr)};
607+
std::optional<evaluate::DynamicType> dyType;
608+
if (expr) {
609+
dyType = expr->GetType();
610+
}
611+
if (!expr || !dyType) {
612+
context_.Say(parser::FindSourceLocation(*pexpr),
613+
"I/O unit must be a character variable or scalar integer expression"_err_en_US);
614+
} else if (dyType->category() != TypeCategory::Integer) {
615+
context_.Say(parser::FindSourceLocation(*pexpr),
616+
"I/O unit must be a character variable or a scalar integer expression, but is an expression of type %s"_err_en_US,
617+
parser::ToUpperCaseLetters(dyType->AsFortran()));
618+
} else if (expr->Rank() != 0) {
619+
context_.Say(parser::FindSourceLocation(*pexpr),
620+
"I/O unit number must be scalar"_err_en_US);
621+
}
622+
SetSpecifier(IoSpecKind::Unit);
623+
flags_.set(Flag::NumberUnit);
601624
}
602625
}
603626

flang/test/Semantics/io03.f90

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,22 @@
171171
!ERROR: ID kind (2) is smaller than default INTEGER kind (4)
172172
read(10, id=id2, asynchronous='yes') jj
173173

174+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
175+
read((msg), *)
176+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(KIND=1,LEN=8_8)
177+
read("a string", *)
178+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
179+
read(msg//msg, *)
180+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type LOGICAL(4)
181+
read(.true., *)
182+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type REAL(4)
183+
read(1.0, *)
184+
read(internal_fileA, *)
185+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
186+
read((internal_fileA), *)
187+
!ERROR: I/O unit number must be scalar
188+
read([1,2,3], *)
189+
174190
9 continue
175191
end
176192

flang/test/Semantics/io04.f90

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,23 @@
138138

139139
write(*, '(X)')
140140

141+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
142+
write((msg), *)
143+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(KIND=1,LEN=8_8)
144+
write("a string", *)
145+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
146+
write(msg//msg, *)
147+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type LOGICAL(4)
148+
write(.true., *)
149+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type REAL(4)
150+
write(1.0, *)
151+
write(internal_fileA, *)
152+
!! Not sure why this isn't an error with this message: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
153+
write((internal_fileA), *)
154+
!ERROR: I/O unit number must be scalar
155+
write([1,2,3], *)
156+
157+
141158
!ERROR: Output item must not be a procedure
142159
print*, procptr
143160
!ERROR: Output item must not be a procedure

flang/test/Semantics/unsigned-errors.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
!ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types INTEGER(4) and UNSIGNED(4)
6565
j = 1u
6666

67-
!ERROR: Must have INTEGER type, but is UNSIGNED(4)
67+
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type UNSIGNED(4)
6868
write(6u,*) 'hi'
6969

7070
!ERROR: ARITHMETIC IF expression must not be an UNSIGNED expression

0 commit comments

Comments
 (0)