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