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 void CheckForUselessIomsg() const; 129 130 parser::Message *CheckForBadIoType(const evaluate::DynamicType &, 131 common::DefinedIo, parser::CharBlock) const; 132 void CheckForBadIoType( 133 const SomeExpr &, common::DefinedIo, parser::CharBlock) const; 134 parser::Message *CheckForBadIoType( 135 const Symbol &, common::DefinedIo, parser::CharBlock) const; 136 137 void CheckNamelist( 138 const Symbol &, common::DefinedIo, parser::CharBlock) const; 139 140 void Init(IoStmtKind s) { 141 stmt_ = s; 142 specifierSet_.reset(); 143 flags_.reset(); 144 } 145 146 void Done() { stmt_ = IoStmtKind::None; } 147 148 SemanticsContext &context_; 149 IoStmtKind stmt_{IoStmtKind::None}; 150 common::EnumSet<IoSpecKind, common::IoSpecKind_enumSize> specifierSet_; 151 common::EnumSet<Flag, Flag_enumSize> flags_; 152 }; 153 154 } // namespace Fortran::semantics 155 #endif // FORTRAN_SEMANTICS_CHECK_IO_H_ 156