1 //===-- include/flang/Semantics/semantics.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_SEMANTICS_H_ 10 #define FORTRAN_SEMANTICS_SEMANTICS_H_ 11 12 #include "scope.h" 13 #include "symbol.h" 14 #include "flang/Common/Fortran-features.h" 15 #include "flang/Evaluate/common.h" 16 #include "flang/Evaluate/intrinsics.h" 17 #include "flang/Parser/message.h" 18 #include <iosfwd> 19 #include <set> 20 #include <string> 21 #include <vector> 22 23 namespace llvm { 24 class raw_ostream; 25 } 26 27 namespace Fortran::common { 28 class IntrinsicTypeDefaultKinds; 29 } 30 31 namespace Fortran::parser { 32 struct Name; 33 struct Program; 34 class AllCookedSources; 35 struct AssociateConstruct; 36 struct BlockConstruct; 37 struct CaseConstruct; 38 struct DoConstruct; 39 struct ChangeTeamConstruct; 40 struct CriticalConstruct; 41 struct ForallConstruct; 42 struct IfConstruct; 43 struct SelectRankConstruct; 44 struct SelectTypeConstruct; 45 struct Variable; 46 struct WhereConstruct; 47 } // namespace Fortran::parser 48 49 namespace Fortran::semantics { 50 51 class Symbol; 52 53 using ConstructNode = std::variant<const parser::AssociateConstruct *, 54 const parser::BlockConstruct *, const parser::CaseConstruct *, 55 const parser::ChangeTeamConstruct *, const parser::CriticalConstruct *, 56 const parser::DoConstruct *, const parser::ForallConstruct *, 57 const parser::IfConstruct *, const parser::SelectRankConstruct *, 58 const parser::SelectTypeConstruct *, const parser::WhereConstruct *>; 59 using ConstructStack = std::vector<ConstructNode>; 60 61 class SemanticsContext { 62 public: 63 SemanticsContext(const common::IntrinsicTypeDefaultKinds &, 64 const common::LanguageFeatureControl &, parser::AllCookedSources &); 65 ~SemanticsContext(); 66 defaultKinds()67 const common::IntrinsicTypeDefaultKinds &defaultKinds() const { 68 return defaultKinds_; 69 } languageFeatures()70 const common::LanguageFeatureControl &languageFeatures() const { 71 return languageFeatures_; 72 }; 73 int GetDefaultKind(TypeCategory) const; doublePrecisionKind()74 int doublePrecisionKind() const { 75 return defaultKinds_.doublePrecisionKind(); 76 } quadPrecisionKind()77 int quadPrecisionKind() const { return defaultKinds_.quadPrecisionKind(); } 78 bool IsEnabled(common::LanguageFeature) const; 79 bool ShouldWarn(common::LanguageFeature) const; location()80 const std::optional<parser::CharBlock> &location() const { return location_; } searchDirectories()81 const std::vector<std::string> &searchDirectories() const { 82 return searchDirectories_; 83 } moduleDirectory()84 const std::string &moduleDirectory() const { return moduleDirectory_; } moduleFileSuffix()85 const std::string &moduleFileSuffix() const { return moduleFileSuffix_; } warnOnNonstandardUsage()86 bool warnOnNonstandardUsage() const { return warnOnNonstandardUsage_; } warningsAreErrors()87 bool warningsAreErrors() const { return warningsAreErrors_; } debugModuleWriter()88 bool debugModuleWriter() const { return debugModuleWriter_; } intrinsics()89 const evaluate::IntrinsicProcTable &intrinsics() const { return intrinsics_; } globalScope()90 Scope &globalScope() { return globalScope_; } messages()91 parser::Messages &messages() { return messages_; } foldingContext()92 evaluate::FoldingContext &foldingContext() { return foldingContext_; } allCookedSources()93 parser::AllCookedSources &allCookedSources() { return allCookedSources_; } 94 set_location(const std::optional<parser::CharBlock> & location)95 SemanticsContext &set_location( 96 const std::optional<parser::CharBlock> &location) { 97 location_ = location; 98 return *this; 99 } set_searchDirectories(const std::vector<std::string> & x)100 SemanticsContext &set_searchDirectories(const std::vector<std::string> &x) { 101 searchDirectories_ = x; 102 return *this; 103 } set_moduleDirectory(const std::string & x)104 SemanticsContext &set_moduleDirectory(const std::string &x) { 105 moduleDirectory_ = x; 106 return *this; 107 } set_moduleFileSuffix(const std::string & x)108 SemanticsContext &set_moduleFileSuffix(const std::string &x) { 109 moduleFileSuffix_ = x; 110 return *this; 111 } set_warnOnNonstandardUsage(bool x)112 SemanticsContext &set_warnOnNonstandardUsage(bool x) { 113 warnOnNonstandardUsage_ = x; 114 return *this; 115 } set_warningsAreErrors(bool x)116 SemanticsContext &set_warningsAreErrors(bool x) { 117 warningsAreErrors_ = x; 118 return *this; 119 } 120 set_debugModuleWriter(bool x)121 SemanticsContext &set_debugModuleWriter(bool x) { 122 debugModuleWriter_ = x; 123 return *this; 124 } 125 126 const DeclTypeSpec &MakeNumericType(TypeCategory, int kind = 0); 127 const DeclTypeSpec &MakeLogicalType(int kind = 0); 128 129 bool AnyFatalError() const; 130 131 // Test or set the Error flag on a Symbol 132 bool HasError(const Symbol &); 133 bool HasError(const Symbol *); 134 bool HasError(const parser::Name &); 135 void SetError(const Symbol &, bool = true); 136 Say(A &&...args)137 template <typename... A> parser::Message &Say(A &&...args) { 138 CHECK(location_); 139 return messages_.Say(*location_, std::forward<A>(args)...); 140 } 141 template <typename... A> Say(parser::CharBlock at,A &&...args)142 parser::Message &Say(parser::CharBlock at, A &&...args) { 143 return messages_.Say(at, std::forward<A>(args)...); 144 } Say(parser::Message && msg)145 parser::Message &Say(parser::Message &&msg) { 146 return messages_.Say(std::move(msg)); 147 } 148 template <typename... A> SayWithDecl(const Symbol & symbol,const parser::CharBlock & at,parser::MessageFixedText && msg,A &&...args)149 void SayWithDecl(const Symbol &symbol, const parser::CharBlock &at, 150 parser::MessageFixedText &&msg, A &&...args) { 151 auto &message{Say(at, std::move(msg), args...)}; 152 evaluate::AttachDeclaration(&message, symbol); 153 } 154 155 const Scope &FindScope(parser::CharBlock) const; 156 Scope &FindScope(parser::CharBlock); 157 constructStack()158 const ConstructStack &constructStack() const { return constructStack_; } PushConstruct(const N & node)159 template <typename N> void PushConstruct(const N &node) { 160 constructStack_.emplace_back(&node); 161 } 162 void PopConstruct(); 163 164 ENUM_CLASS(IndexVarKind, DO, FORALL) 165 // Check to see if a variable being redefined is a DO or FORALL index. 166 // If so, emit a message. 167 void WarnIndexVarRedefine(const parser::CharBlock &, const Symbol &); 168 void CheckIndexVarRedefine(const parser::CharBlock &, const Symbol &); 169 void CheckIndexVarRedefine(const parser::Variable &); 170 void CheckIndexVarRedefine(const parser::Name &); 171 void ActivateIndexVar(const parser::Name &, IndexVarKind); 172 void DeactivateIndexVar(const parser::Name &); 173 SymbolVector GetIndexVars(IndexVarKind); 174 SourceName SaveTempName(std::string &&); 175 SourceName GetTempName(const Scope &); 176 177 private: 178 void CheckIndexVarRedefine( 179 const parser::CharBlock &, const Symbol &, parser::MessageFixedText &&); 180 void CheckError(const Symbol &); 181 182 const common::IntrinsicTypeDefaultKinds &defaultKinds_; 183 const common::LanguageFeatureControl languageFeatures_; 184 parser::AllCookedSources &allCookedSources_; 185 std::optional<parser::CharBlock> location_; 186 std::vector<std::string> searchDirectories_; 187 std::string moduleDirectory_{"."s}; 188 std::string moduleFileSuffix_{".mod"}; 189 bool warnOnNonstandardUsage_{false}; 190 bool warningsAreErrors_{false}; 191 bool debugModuleWriter_{false}; 192 const evaluate::IntrinsicProcTable intrinsics_; 193 Scope globalScope_; 194 parser::Messages messages_; 195 evaluate::FoldingContext foldingContext_; 196 ConstructStack constructStack_; 197 struct IndexVarInfo { 198 parser::CharBlock location; 199 IndexVarKind kind; 200 }; 201 std::map<SymbolRef, const IndexVarInfo> activeIndexVars_; 202 std::set<SymbolRef> errorSymbols_; 203 std::set<std::string> tempNames_; 204 }; 205 206 class Semantics { 207 public: 208 explicit Semantics(SemanticsContext &context, parser::Program &program, 209 parser::CharBlock charBlock, bool debugModuleWriter = false) 210 : context_{context}, program_{program} { 211 context.set_debugModuleWriter(debugModuleWriter); 212 context.globalScope().AddSourceRange(charBlock); 213 } 214 context()215 SemanticsContext &context() const { return context_; } 216 bool Perform(); FindScope(const parser::CharBlock & where)217 const Scope &FindScope(const parser::CharBlock &where) const { 218 return context_.FindScope(where); 219 } AnyFatalError()220 bool AnyFatalError() const { return context_.AnyFatalError(); } 221 void EmitMessages(llvm::raw_ostream &) const; 222 void DumpSymbols(llvm::raw_ostream &); 223 void DumpSymbolsSources(llvm::raw_ostream &) const; 224 225 private: 226 SemanticsContext &context_; 227 parser::Program &program_; 228 }; 229 230 // Base class for semantics checkers. 231 struct BaseChecker { EnterBaseChecker232 template <typename N> void Enter(const N &) {} LeaveBaseChecker233 template <typename N> void Leave(const N &) {} 234 }; 235 } // namespace Fortran::semantics 236 #endif 237