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 // Locate and process the contents of a built-in module on demand 178 Scope *GetBuiltinModule(const char *name); 179 180 // Defines builtinsScope_ from the __Fortran_builtins module 181 void UseFortranBuiltinsModule(); GetBuiltinsScope()182 const Scope *GetBuiltinsScope() const { return builtinsScope_; } 183 184 private: 185 void CheckIndexVarRedefine( 186 const parser::CharBlock &, const Symbol &, parser::MessageFixedText &&); 187 void CheckError(const Symbol &); 188 189 const common::IntrinsicTypeDefaultKinds &defaultKinds_; 190 const common::LanguageFeatureControl languageFeatures_; 191 parser::AllCookedSources &allCookedSources_; 192 std::optional<parser::CharBlock> location_; 193 std::vector<std::string> searchDirectories_; 194 std::string moduleDirectory_{"."s}; 195 std::string moduleFileSuffix_{".mod"}; 196 bool warnOnNonstandardUsage_{false}; 197 bool warningsAreErrors_{false}; 198 bool debugModuleWriter_{false}; 199 const evaluate::IntrinsicProcTable intrinsics_; 200 Scope globalScope_; 201 parser::Messages messages_; 202 evaluate::FoldingContext foldingContext_; 203 ConstructStack constructStack_; 204 struct IndexVarInfo { 205 parser::CharBlock location; 206 IndexVarKind kind; 207 }; 208 std::map<SymbolRef, const IndexVarInfo, SymbolAddressCompare> 209 activeIndexVars_; 210 UnorderedSymbolSet errorSymbols_; 211 std::set<std::string> tempNames_; 212 const Scope *builtinsScope_{nullptr}; // module __Fortran_builtins 213 }; 214 215 class Semantics { 216 public: 217 explicit Semantics(SemanticsContext &context, parser::Program &program, 218 bool debugModuleWriter = false) 219 : context_{context}, program_{program} { 220 context.set_debugModuleWriter(debugModuleWriter); 221 } 222 context()223 SemanticsContext &context() const { return context_; } 224 bool Perform(); FindScope(const parser::CharBlock & where)225 const Scope &FindScope(const parser::CharBlock &where) const { 226 return context_.FindScope(where); 227 } AnyFatalError()228 bool AnyFatalError() const { return context_.AnyFatalError(); } 229 void EmitMessages(llvm::raw_ostream &) const; 230 void DumpSymbols(llvm::raw_ostream &); 231 void DumpSymbolsSources(llvm::raw_ostream &) const; 232 233 private: 234 SemanticsContext &context_; 235 parser::Program &program_; 236 }; 237 238 // Base class for semantics checkers. 239 struct BaseChecker { EnterBaseChecker240 template <typename N> void Enter(const N &) {} LeaveBaseChecker241 template <typename N> void Leave(const N &) {} 242 }; 243 } // namespace Fortran::semantics 244 #endif 245