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: IoChecker(SemanticsContext & context)24 explicit IoChecker(SemanticsContext &context) : context_{context} {} 25 Enter(const parser::BackspaceStmt &)26 void Enter(const parser::BackspaceStmt &) { Init(IoStmtKind::Backspace); } Enter(const parser::CloseStmt &)27 void Enter(const parser::CloseStmt &) { Init(IoStmtKind::Close); } Enter(const parser::EndfileStmt &)28 void Enter(const parser::EndfileStmt &) { Init(IoStmtKind::Endfile); } Enter(const parser::FlushStmt &)29 void Enter(const parser::FlushStmt &) { Init(IoStmtKind::Flush); } Enter(const parser::InquireStmt &)30 void Enter(const parser::InquireStmt &) { Init(IoStmtKind::Inquire); } Enter(const parser::OpenStmt &)31 void Enter(const parser::OpenStmt &) { Init(IoStmtKind::Open); } Enter(const parser::PrintStmt &)32 void Enter(const parser::PrintStmt &) { Init(IoStmtKind::Print); } Enter(const parser::ReadStmt &)33 void Enter(const parser::ReadStmt &) { Init(IoStmtKind::Read); } Enter(const parser::RewindStmt &)34 void Enter(const parser::RewindStmt &) { Init(IoStmtKind::Rewind); } Enter(const parser::WaitStmt &)35 void Enter(const parser::WaitStmt &) { Init(IoStmtKind::Wait); } Enter(const parser::WriteStmt &)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. ENUM_CLASS(Flag,IoControlList,InternalUnit,NumberUnit,StarUnit,CharFmt,LabelFmt,StarFmt,AssignFmt,FmtOrNml,KnownAccess,AccessDirect,AccessStream,AdvanceYes,AsynchronousYes,KnownStatus,StatusNew,StatusReplace,StatusScratch,DataList)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 = 90 evaluate::Type<common::TypeCategory::Character, 1>; 91 if (const SomeExpr * expr{GetExpr(x)}) { 92 const auto foldExpr{ 93 evaluate::Fold(context_.foldingContext(), common::Clone(*expr))}; 94 if constexpr (std::is_same_v<R, std::string>) { 95 return evaluate::GetScalarConstantValue<DefaultCharConstantType>( 96 foldExpr); 97 } else { 98 static_assert(std::is_same_v<R, std::int64_t>, "unexpected type"); 99 return evaluate::ToInt64(foldExpr); 100 } 101 } 102 return std::nullopt; 103 } 104 105 void LeaveReadWrite() const; 106 107 void SetSpecifier(IoSpecKind); 108 109 void CheckStringValue( 110 IoSpecKind, const std::string &, const parser::CharBlock &) const; 111 112 void CheckForRequiredSpecifier(IoSpecKind) const; 113 void CheckForRequiredSpecifier(bool, const std::string &) const; 114 void CheckForRequiredSpecifier(IoSpecKind, IoSpecKind) const; 115 void CheckForRequiredSpecifier(IoSpecKind, bool, const std::string &) const; 116 void CheckForRequiredSpecifier(bool, const std::string &, IoSpecKind) const; 117 void CheckForRequiredSpecifier( 118 bool, const std::string &, bool, const std::string &) const; 119 120 void CheckForProhibitedSpecifier(IoSpecKind) const; 121 void CheckForProhibitedSpecifier(IoSpecKind, IoSpecKind) const; 122 void CheckForProhibitedSpecifier(IoSpecKind, bool, const std::string &) const; 123 void CheckForProhibitedSpecifier(bool, const std::string &, IoSpecKind) const; 124 125 template <typename A> 126 void CheckForDefinableVariable(const A &var, const std::string &s) const; 127 128 void CheckForPureSubprogram() const; 129 Init(IoStmtKind s)130 void Init(IoStmtKind s) { 131 stmt_ = s; 132 specifierSet_.reset(); 133 flags_.reset(); 134 } 135 Done()136 void Done() { stmt_ = IoStmtKind::None; } 137 138 SemanticsContext &context_; 139 IoStmtKind stmt_{IoStmtKind::None}; 140 common::EnumSet<IoSpecKind, common::IoSpecKind_enumSize> specifierSet_; 141 common::EnumSet<Flag, Flag_enumSize> flags_; 142 }; 143 144 } // namespace Fortran::semantics 145 #endif // FORTRAN_SEMANTICS_CHECK_IO_H_ 146