1 | //===-- lib/Semantics/check-io.h --------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef FORTRAN_SEMANTICS_CHECK_IO_H_ |
10 | #define FORTRAN_SEMANTICS_CHECK_IO_H_ |
11 | |
12 | #include "flang/Common/enum-set.h" |
13 | #include "flang/Parser/parse-tree.h" |
14 | #include "flang/Semantics/semantics.h" |
15 | #include "flang/Semantics/tools.h" |
16 | |
17 | namespace Fortran::semantics { |
18 | |
19 | using common::IoSpecKind; |
20 | using common::IoStmtKind; |
21 | |
22 | class IoChecker : public virtual BaseChecker { |
23 | public: |
24 | explicit IoChecker(SemanticsContext &context) : context_{context} {} |
25 | |
26 | void Enter(const parser::BackspaceStmt &) { Init(IoStmtKind::Backspace); } |
27 | void Enter(const parser::CloseStmt &) { Init(IoStmtKind::Close); } |
28 | void Enter(const parser::EndfileStmt &) { Init(IoStmtKind::Endfile); } |
29 | void Enter(const parser::FlushStmt &) { Init(IoStmtKind::Flush); } |
30 | void Enter(const parser::InquireStmt &) { Init(IoStmtKind::Inquire); } |
31 | void Enter(const parser::OpenStmt &) { Init(IoStmtKind::Open); } |
32 | void Enter(const parser::PrintStmt &) { Init(IoStmtKind::Print); } |
33 | void Enter(const parser::ReadStmt &) { Init(IoStmtKind::Read); } |
34 | void Enter(const parser::RewindStmt &) { Init(IoStmtKind::Rewind); } |
35 | void Enter(const parser::WaitStmt &) { Init(IoStmtKind::Wait); } |
36 | void Enter(const parser::WriteStmt &) { Init(IoStmtKind::Write); } |
37 | |
38 | void Enter( |
39 | const parser::Statement<common::Indirection<parser::FormatStmt>> &); |
40 | |
41 | void Enter(const parser::ConnectSpec &); |
42 | void Enter(const parser::ConnectSpec::CharExpr &); |
43 | void Enter(const parser::ConnectSpec::Newunit &); |
44 | void Enter(const parser::ConnectSpec::Recl &); |
45 | void Enter(const parser::EndLabel &); |
46 | void Enter(const parser::EorLabel &); |
47 | void Enter(const parser::ErrLabel &); |
48 | void Enter(const parser::FileUnitNumber &); |
49 | void Enter(const parser::Format &); |
50 | void Enter(const parser::IdExpr &); |
51 | void Enter(const parser::IdVariable &); |
52 | void Enter(const parser::InputItem &); |
53 | void Enter(const parser::InquireSpec &); |
54 | void Enter(const parser::InquireSpec::CharVar &); |
55 | void Enter(const parser::InquireSpec::IntVar &); |
56 | void Enter(const parser::InquireSpec::LogVar &); |
57 | void Enter(const parser::IoControlSpec &); |
58 | void Enter(const parser::IoControlSpec::Asynchronous &); |
59 | void Enter(const parser::IoControlSpec::CharExpr &); |
60 | void Enter(const parser::IoControlSpec::Pos &); |
61 | void Enter(const parser::IoControlSpec::Rec &); |
62 | void Enter(const parser::IoControlSpec::Size &); |
63 | void Enter(const parser::IoUnit &); |
64 | void Enter(const parser::MsgVariable &); |
65 | void Enter(const parser::OutputItem &); |
66 | void Enter(const parser::StatusExpr &); |
67 | void Enter(const parser::StatVariable &); |
68 | |
69 | void Leave(const parser::BackspaceStmt &); |
70 | void Leave(const parser::CloseStmt &); |
71 | void Leave(const parser::EndfileStmt &); |
72 | void Leave(const parser::FlushStmt &); |
73 | void Leave(const parser::InquireStmt &); |
74 | void Leave(const parser::OpenStmt &); |
75 | void Leave(const parser::PrintStmt &); |
76 | void Leave(const parser::ReadStmt &); |
77 | void Leave(const parser::RewindStmt &); |
78 | void Leave(const parser::WaitStmt &); |
79 | void Leave(const parser::WriteStmt &); |
80 | |
81 | private: |
82 | // Presence flag values. |
83 | ENUM_CLASS(Flag, IoControlList, InternalUnit, NumberUnit, StarUnit, CharFmt, |
84 | LabelFmt, StarFmt, AssignFmt, FmtOrNml, KnownAccess, AccessDirect, |
85 | AccessStream, AdvanceYes, AsynchronousYes, KnownStatus, StatusNew, |
86 | StatusReplace, StatusScratch, DataList) |
87 | |
88 | template <typename R, typename T> std::optional<R> GetConstExpr(const T &x) { |
89 | using DefaultCharConstantType = evaluate::Ascii; |
90 | if (const SomeExpr * expr{GetExpr(context_, x)}) { |
91 | const auto foldExpr{ |
92 | evaluate::Fold(context_.foldingContext(), common::Clone(*expr))}; |
93 | if constexpr (std::is_same_v<R, std::string>) { |
94 | return evaluate::GetScalarConstantValue<DefaultCharConstantType>( |
95 | foldExpr); |
96 | } else { |
97 | static_assert(std::is_same_v<R, std::int64_t>, "unexpected type" ); |
98 | return evaluate::ToInt64(foldExpr); |
99 | } |
100 | } |
101 | return std::nullopt; |
102 | } |
103 | |
104 | void LeaveReadWrite() const; |
105 | |
106 | void SetSpecifier(IoSpecKind); |
107 | |
108 | void CheckStringValue( |
109 | IoSpecKind, const std::string &, const parser::CharBlock &) const; |
110 | |
111 | void CheckForRequiredSpecifier(IoSpecKind) const; |
112 | void CheckForRequiredSpecifier(bool, const std::string &) const; |
113 | void CheckForRequiredSpecifier(IoSpecKind, IoSpecKind) const; |
114 | void CheckForRequiredSpecifier(IoSpecKind, bool, const std::string &) const; |
115 | void CheckForRequiredSpecifier(bool, const std::string &, IoSpecKind) const; |
116 | void CheckForRequiredSpecifier( |
117 | bool, const std::string &, bool, const std::string &) const; |
118 | |
119 | void CheckForProhibitedSpecifier(IoSpecKind) const; |
120 | void CheckForProhibitedSpecifier(IoSpecKind, IoSpecKind) const; |
121 | void CheckForProhibitedSpecifier(IoSpecKind, bool, const std::string &) const; |
122 | void CheckForProhibitedSpecifier(bool, const std::string &, IoSpecKind) const; |
123 | |
124 | template <typename A> |
125 | void CheckForDefinableVariable(const A &var, const std::string &s) const; |
126 | |
127 | void CheckForPureSubprogram() const; |
128 | |
129 | parser::Message *CheckForBadIoType(const evaluate::DynamicType &, |
130 | common::DefinedIo, parser::CharBlock) const; |
131 | void CheckForBadIoType( |
132 | const SomeExpr &, common::DefinedIo, parser::CharBlock) const; |
133 | parser::Message *CheckForBadIoType( |
134 | const Symbol &, common::DefinedIo, parser::CharBlock) const; |
135 | |
136 | void CheckNamelist( |
137 | const Symbol &, common::DefinedIo, parser::CharBlock) const; |
138 | |
139 | void Init(IoStmtKind s) { |
140 | stmt_ = s; |
141 | specifierSet_.reset(); |
142 | flags_.reset(); |
143 | } |
144 | |
145 | void Done() { stmt_ = IoStmtKind::None; } |
146 | |
147 | SemanticsContext &context_; |
148 | IoStmtKind stmt_{IoStmtKind::None}; |
149 | common::EnumSet<IoSpecKind, common::IoSpecKind_enumSize> specifierSet_; |
150 | common::EnumSet<Flag, Flag_enumSize> flags_; |
151 | }; |
152 | |
153 | } // namespace Fortran::semantics |
154 | #endif // FORTRAN_SEMANTICS_CHECK_IO_H_ |
155 | |