mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 19:06:44 +00:00
[Flang] Give a more specific error message for expressions where an IO Unit is expected (#126970)
This PR fixes #125446 by specializing the error message that is generated when an arbitrary expression is used as an IO Unit. See the tests for specific examples, but the general gist is that if you use a non-variable expression as the IO unit argument to a read or write, you now get a more specific error message indicating the the expression could have been a scalar integer expression or character variable.
This commit is contained in:
parent
236fa506d4
commit
374c470cd1
@ -2642,7 +2642,7 @@ WRAPPER_CLASS(FileUnitNumber, ScalarIntExpr);
|
||||
// symbols are known.
|
||||
struct IoUnit {
|
||||
UNION_CLASS_BOILERPLATE(IoUnit);
|
||||
std::variant<Variable, FileUnitNumber, Star> u;
|
||||
std::variant<Variable, common::Indirection<Expr>, Star> u;
|
||||
};
|
||||
|
||||
// R1206 file-name-expr -> scalar-default-char-expr
|
||||
|
@ -1841,7 +1841,9 @@ static mlir::Value genIOUnit(Fortran::lower::AbstractConverter &converter,
|
||||
int defaultUnitNumber) {
|
||||
auto &builder = converter.getFirOpBuilder();
|
||||
if (iounit)
|
||||
if (auto *e = std::get_if<Fortran::parser::FileUnitNumber>(&iounit->u))
|
||||
if (auto *e =
|
||||
std::get_if<Fortran::common::Indirection<Fortran::parser::Expr>>(
|
||||
&iounit->u))
|
||||
return genIOUnitNumber(converter, loc, Fortran::semantics::GetExpr(*e),
|
||||
ty, csi, stmtCtx);
|
||||
return builder.create<mlir::arith::ConstantOp>(
|
||||
|
@ -23,8 +23,12 @@ namespace Fortran::parser {
|
||||
// R905 char-variable -> variable
|
||||
// "char-variable" is attempted first since it's not type constrained but
|
||||
// syntactically ambiguous with "file-unit-number", which is constrained.
|
||||
// Note, "file-unit-number" is replaced by "expr" to allow for better
|
||||
// error messages.
|
||||
TYPE_PARSER(construct<IoUnit>(variable / lookAhead(space / ",);\n"_ch)) ||
|
||||
construct<IoUnit>(fileUnitNumber) || construct<IoUnit>(star))
|
||||
construct<IoUnit>(
|
||||
indirect(expr) / (lookAhead(space >> ",)"_ch) || atEndOfStmt)) ||
|
||||
construct<IoUnit>(star))
|
||||
|
||||
// R1202 file-unit-number -> scalar-int-expr
|
||||
TYPE_PARSER(construct<FileUnitNumber>(
|
||||
|
@ -9,7 +9,9 @@
|
||||
#include "check-io.h"
|
||||
#include "definable.h"
|
||||
#include "flang/Common/format.h"
|
||||
#include "flang/Common/indirection.h"
|
||||
#include "flang/Evaluate/tools.h"
|
||||
#include "flang/Parser/characters.h"
|
||||
#include "flang/Parser/tools.h"
|
||||
#include "flang/Semantics/expression.h"
|
||||
#include "flang/Semantics/tools.h"
|
||||
@ -576,8 +578,9 @@ void IoChecker::Enter(const parser::IoUnit &spec) {
|
||||
std::move(mutableVar.u))};
|
||||
newExpr.source = source;
|
||||
newExpr.typedExpr = std::move(typedExpr);
|
||||
mutableSpec.u = parser::FileUnitNumber{
|
||||
parser::ScalarIntExpr{parser::IntExpr{std::move(newExpr)}}};
|
||||
mutableSpec.u = common::Indirection<parser::Expr>{std::move(newExpr)};
|
||||
SetSpecifier(IoSpecKind::Unit);
|
||||
flags_.set(Flag::NumberUnit);
|
||||
} else if (!dyType || dyType->category() != TypeCategory::Character) {
|
||||
SetSpecifier(IoSpecKind::Unit);
|
||||
context_.Say(parser::FindSourceLocation(*var),
|
||||
@ -598,6 +601,26 @@ void IoChecker::Enter(const parser::IoUnit &spec) {
|
||||
} else if (std::get_if<parser::Star>(&spec.u)) {
|
||||
SetSpecifier(IoSpecKind::Unit);
|
||||
flags_.set(Flag::StarUnit);
|
||||
} else if (const common::Indirection<parser::Expr> *pexpr{
|
||||
std::get_if<common::Indirection<parser::Expr>>(&spec.u)}) {
|
||||
const auto *expr{GetExpr(context_, *pexpr)};
|
||||
std::optional<evaluate::DynamicType> dyType;
|
||||
if (expr) {
|
||||
dyType = expr->GetType();
|
||||
}
|
||||
if (!expr || !dyType) {
|
||||
context_.Say(parser::FindSourceLocation(*pexpr),
|
||||
"I/O unit must be a character variable or scalar integer expression"_err_en_US);
|
||||
} else if (dyType->category() != TypeCategory::Integer) {
|
||||
context_.Say(parser::FindSourceLocation(*pexpr),
|
||||
"I/O unit must be a character variable or a scalar integer expression, but is an expression of type %s"_err_en_US,
|
||||
parser::ToUpperCaseLetters(dyType->AsFortran()));
|
||||
} else if (expr->Rank() != 0) {
|
||||
context_.Say(parser::FindSourceLocation(*pexpr),
|
||||
"I/O unit number must be scalar"_err_en_US);
|
||||
}
|
||||
SetSpecifier(IoSpecKind::Unit);
|
||||
flags_.set(Flag::NumberUnit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,6 +171,22 @@
|
||||
!ERROR: ID kind (2) is smaller than default INTEGER kind (4)
|
||||
read(10, id=id2, asynchronous='yes') jj
|
||||
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
|
||||
read((msg), *)
|
||||
!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)
|
||||
read("a string", *)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
|
||||
read(msg//msg, *)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type LOGICAL(4)
|
||||
read(.true., *)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type REAL(4)
|
||||
read(1.0, *)
|
||||
read(internal_fileA, *)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
|
||||
read((internal_fileA), *)
|
||||
!ERROR: I/O unit number must be scalar
|
||||
read([1,2,3], *)
|
||||
|
||||
9 continue
|
||||
end
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
character(kind=1,len=100) msg
|
||||
character(20) sign
|
||||
character, parameter :: const_internal_file*(*) = "(I6)"
|
||||
character(kind=1,len=50) internal_fileA(20)
|
||||
integer*1 stat1, id1
|
||||
integer*2 stat2
|
||||
integer*4 stat4
|
||||
@ -138,6 +139,23 @@
|
||||
|
||||
write(*, '(X)')
|
||||
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
|
||||
write((msg), *)
|
||||
!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)
|
||||
write("a string", *)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
|
||||
write(msg//msg, *)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type LOGICAL(4)
|
||||
write(.true., *)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type REAL(4)
|
||||
write(1.0, *)
|
||||
write(internal_fileA, *)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(1)
|
||||
write((internal_fileA), *)
|
||||
!ERROR: I/O unit number must be scalar
|
||||
write([1,2,3], *)
|
||||
|
||||
|
||||
!ERROR: Output item must not be a procedure
|
||||
print*, procptr
|
||||
!ERROR: Output item must not be a procedure
|
||||
|
@ -64,7 +64,7 @@ u = 1
|
||||
!ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types INTEGER(4) and UNSIGNED(4)
|
||||
j = 1u
|
||||
|
||||
!ERROR: Must have INTEGER type, but is UNSIGNED(4)
|
||||
!ERROR: I/O unit must be a character variable or a scalar integer expression, but is an expression of type UNSIGNED(4)
|
||||
write(6u,*) 'hi'
|
||||
|
||||
!ERROR: ARITHMETIC IF expression must not be an UNSIGNED expression
|
||||
|
Loading…
x
Reference in New Issue
Block a user