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/Evaluate/target.h" 18 #include "flang/Parser/message.h" 19 #include <iosfwd> 20 #include <set> 21 #include <string> 22 #include <vector> 23 24 namespace llvm { 25 class raw_ostream; 26 } 27 28 namespace Fortran::common { 29 class IntrinsicTypeDefaultKinds; 30 } 31 32 namespace Fortran::parser { 33 struct Name; 34 struct Program; 35 class AllCookedSources; 36 struct AssociateConstruct; 37 struct BlockConstruct; 38 struct CaseConstruct; 39 struct DoConstruct; 40 struct ChangeTeamConstruct; 41 struct CriticalConstruct; 42 struct ForallConstruct; 43 struct IfConstruct; 44 struct SelectRankConstruct; 45 struct SelectTypeConstruct; 46 struct Variable; 47 struct WhereConstruct; 48 } // namespace Fortran::parser 49 50 namespace Fortran::semantics { 51 52 class Symbol; 53 class CommonBlockMap; 54 using CommonBlockList = std::vector<std::pair<SymbolRef, std::size_t>>; 55 56 using ConstructNode = std::variant<const parser::AssociateConstruct *, 57 const parser::BlockConstruct *, const parser::CaseConstruct *, 58 const parser::ChangeTeamConstruct *, const parser::CriticalConstruct *, 59 const parser::DoConstruct *, const parser::ForallConstruct *, 60 const parser::IfConstruct *, const parser::SelectRankConstruct *, 61 const parser::SelectTypeConstruct *, const parser::WhereConstruct *>; 62 using ConstructStack = std::vector<ConstructNode>; 63 64 class SemanticsContext { 65 public: 66 SemanticsContext(const common::IntrinsicTypeDefaultKinds &, 67 const common::LanguageFeatureControl &, parser::AllCookedSources &); 68 ~SemanticsContext(); 69 defaultKinds()70 const common::IntrinsicTypeDefaultKinds &defaultKinds() const { 71 return defaultKinds_; 72 } languageFeatures()73 const common::LanguageFeatureControl &languageFeatures() const { 74 return languageFeatures_; 75 }; 76 int GetDefaultKind(TypeCategory) const; doublePrecisionKind()77 int doublePrecisionKind() const { 78 return defaultKinds_.doublePrecisionKind(); 79 } quadPrecisionKind()80 int quadPrecisionKind() const { return defaultKinds_.quadPrecisionKind(); } IsEnabled(common::LanguageFeature feature)81 bool IsEnabled(common::LanguageFeature feature) const { 82 return languageFeatures_.IsEnabled(feature); 83 } ShouldWarn(common::LanguageFeature feature)84 bool ShouldWarn(common::LanguageFeature feature) const { 85 return languageFeatures_.ShouldWarn(feature); 86 } location()87 const std::optional<parser::CharBlock> &location() const { return location_; } searchDirectories()88 const std::vector<std::string> &searchDirectories() const { 89 return searchDirectories_; 90 } intrinsicModuleDirectories()91 const std::vector<std::string> &intrinsicModuleDirectories() const { 92 return intrinsicModuleDirectories_; 93 } moduleDirectory()94 const std::string &moduleDirectory() const { return moduleDirectory_; } moduleFileSuffix()95 const std::string &moduleFileSuffix() const { return moduleFileSuffix_; } warnOnNonstandardUsage()96 bool warnOnNonstandardUsage() const { return warnOnNonstandardUsage_; } warningsAreErrors()97 bool warningsAreErrors() const { return warningsAreErrors_; } debugModuleWriter()98 bool debugModuleWriter() const { return debugModuleWriter_; } intrinsics()99 const evaluate::IntrinsicProcTable &intrinsics() const { return intrinsics_; } targetCharacteristics()100 const evaluate::TargetCharacteristics &targetCharacteristics() const { 101 return targetCharacteristics_; 102 } targetCharacteristics()103 evaluate::TargetCharacteristics &targetCharacteristics() { 104 return targetCharacteristics_; 105 } globalScope()106 Scope &globalScope() { return globalScope_; } intrinsicModulesScope()107 Scope &intrinsicModulesScope() { return intrinsicModulesScope_; } messages()108 parser::Messages &messages() { return messages_; } foldingContext()109 evaluate::FoldingContext &foldingContext() { return foldingContext_; } allCookedSources()110 parser::AllCookedSources &allCookedSources() { return allCookedSources_; } 111 set_location(const std::optional<parser::CharBlock> & location)112 SemanticsContext &set_location( 113 const std::optional<parser::CharBlock> &location) { 114 location_ = location; 115 return *this; 116 } set_searchDirectories(const std::vector<std::string> & x)117 SemanticsContext &set_searchDirectories(const std::vector<std::string> &x) { 118 searchDirectories_ = x; 119 return *this; 120 } set_intrinsicModuleDirectories(const std::vector<std::string> & x)121 SemanticsContext &set_intrinsicModuleDirectories( 122 const std::vector<std::string> &x) { 123 intrinsicModuleDirectories_ = x; 124 return *this; 125 } set_moduleDirectory(const std::string & x)126 SemanticsContext &set_moduleDirectory(const std::string &x) { 127 moduleDirectory_ = x; 128 return *this; 129 } set_moduleFileSuffix(const std::string & x)130 SemanticsContext &set_moduleFileSuffix(const std::string &x) { 131 moduleFileSuffix_ = x; 132 return *this; 133 } set_warnOnNonstandardUsage(bool x)134 SemanticsContext &set_warnOnNonstandardUsage(bool x) { 135 warnOnNonstandardUsage_ = x; 136 return *this; 137 } set_warningsAreErrors(bool x)138 SemanticsContext &set_warningsAreErrors(bool x) { 139 warningsAreErrors_ = x; 140 return *this; 141 } 142 set_debugModuleWriter(bool x)143 SemanticsContext &set_debugModuleWriter(bool x) { 144 debugModuleWriter_ = x; 145 return *this; 146 } 147 148 const DeclTypeSpec &MakeNumericType(TypeCategory, int kind = 0); 149 const DeclTypeSpec &MakeLogicalType(int kind = 0); 150 151 bool AnyFatalError() const; 152 153 // Test or set the Error flag on a Symbol 154 bool HasError(const Symbol &); 155 bool HasError(const Symbol *); 156 bool HasError(const parser::Name &); 157 void SetError(const Symbol &, bool = true); 158 Say(A &&...args)159 template <typename... A> parser::Message &Say(A &&...args) { 160 CHECK(location_); 161 return messages_.Say(*location_, std::forward<A>(args)...); 162 } 163 template <typename... A> Say(parser::CharBlock at,A &&...args)164 parser::Message &Say(parser::CharBlock at, A &&...args) { 165 return messages_.Say(at, std::forward<A>(args)...); 166 } Say(parser::Message && msg)167 parser::Message &Say(parser::Message &&msg) { 168 return messages_.Say(std::move(msg)); 169 } 170 template <typename... A> SayWithDecl(const Symbol & symbol,const parser::CharBlock & at,parser::MessageFixedText && msg,A &&...args)171 void SayWithDecl(const Symbol &symbol, const parser::CharBlock &at, 172 parser::MessageFixedText &&msg, A &&...args) { 173 auto &message{Say(at, std::move(msg), args...)}; 174 evaluate::AttachDeclaration(&message, symbol); 175 } 176 177 const Scope &FindScope(parser::CharBlock) const; 178 Scope &FindScope(parser::CharBlock); 179 180 bool IsInModuleFile(parser::CharBlock) const; 181 constructStack()182 const ConstructStack &constructStack() const { return constructStack_; } PushConstruct(const N & node)183 template <typename N> void PushConstruct(const N &node) { 184 constructStack_.emplace_back(&node); 185 } 186 void PopConstruct(); 187 188 ENUM_CLASS(IndexVarKind, DO, FORALL) 189 // Check to see if a variable being redefined is a DO or FORALL index. 190 // If so, emit a message. 191 void WarnIndexVarRedefine(const parser::CharBlock &, const Symbol &); 192 void CheckIndexVarRedefine(const parser::CharBlock &, const Symbol &); 193 void CheckIndexVarRedefine(const parser::Variable &); 194 void CheckIndexVarRedefine(const parser::Name &); 195 void ActivateIndexVar(const parser::Name &, IndexVarKind); 196 void DeactivateIndexVar(const parser::Name &); 197 SymbolVector GetIndexVars(IndexVarKind); 198 SourceName SaveTempName(std::string &&); 199 SourceName GetTempName(const Scope &); 200 static bool IsTempName(const std::string &); 201 202 // Locate and process the contents of a built-in module on demand 203 Scope *GetBuiltinModule(const char *name); 204 205 // Defines builtinsScope_ from the __Fortran_builtins module 206 void UseFortranBuiltinsModule(); GetBuiltinsScope()207 const Scope *GetBuiltinsScope() const { return builtinsScope_; } 208 209 // Saves a module file's parse tree so that it remains available 210 // during semantics. 211 parser::Program &SaveParseTree(parser::Program &&); 212 213 // Ensures a common block definition does not conflict with previous 214 // appearances in the program and consolidate information about 215 // common blocks at the program level for later checks and lowering. 216 // This can obviously not check any conflicts between different compilation 217 // units (in case such conflicts exist, the behavior will depend on the 218 // linker). 219 void MapCommonBlockAndCheckConflicts(const Symbol &); 220 221 // Get the list of common blocks appearing in the program. If a common block 222 // appears in several subprograms, only one of its appearance is returned in 223 // the list alongside the biggest byte size of all its appearances. 224 // If a common block is initialized in any of its appearances, the list will 225 // contain the appearance with the initialization, otherwise the appearance 226 // with the biggest size is returned. The extra byte size information allows 227 // handling the case where the common block initialization is not the 228 // appearance with the biggest size: the common block will have the biggest 229 // size with the first bytes initialized with the initial value. This is not 230 // standard, if the initialization and biggest size appearances are in 231 // different compilation units, the behavior will depend on the linker. The 232 // linker may have the behavior described before, but it may also keep the 233 // initialized common symbol without extending its size, or have some other 234 // behavior. 235 CommonBlockList GetCommonBlocks() const; 236 237 private: 238 void CheckIndexVarRedefine( 239 const parser::CharBlock &, const Symbol &, parser::MessageFixedText &&); 240 void CheckError(const Symbol &); 241 242 const common::IntrinsicTypeDefaultKinds &defaultKinds_; 243 const common::LanguageFeatureControl languageFeatures_; 244 parser::AllCookedSources &allCookedSources_; 245 std::optional<parser::CharBlock> location_; 246 std::vector<std::string> searchDirectories_; 247 std::vector<std::string> intrinsicModuleDirectories_; 248 std::string moduleDirectory_{"."s}; 249 std::string moduleFileSuffix_{".mod"}; 250 bool warnOnNonstandardUsage_{false}; 251 bool warningsAreErrors_{false}; 252 bool debugModuleWriter_{false}; 253 const evaluate::IntrinsicProcTable intrinsics_; 254 evaluate::TargetCharacteristics targetCharacteristics_; 255 Scope globalScope_; 256 Scope &intrinsicModulesScope_; 257 parser::Messages messages_; 258 evaluate::FoldingContext foldingContext_; 259 ConstructStack constructStack_; 260 struct IndexVarInfo { 261 parser::CharBlock location; 262 IndexVarKind kind; 263 }; 264 std::map<SymbolRef, const IndexVarInfo, SymbolAddressCompare> 265 activeIndexVars_; 266 UnorderedSymbolSet errorSymbols_; 267 std::set<std::string> tempNames_; 268 const Scope *builtinsScope_{nullptr}; // module __Fortran_builtins 269 std::list<parser::Program> modFileParseTrees_; 270 std::unique_ptr<CommonBlockMap> commonBlockMap_; 271 }; 272 273 class Semantics { 274 public: 275 explicit Semantics(SemanticsContext &context, parser::Program &program, 276 bool debugModuleWriter = false) 277 : context_{context}, program_{program} { 278 context.set_debugModuleWriter(debugModuleWriter); 279 } 280 context()281 SemanticsContext &context() const { return context_; } 282 bool Perform(); FindScope(const parser::CharBlock & where)283 const Scope &FindScope(const parser::CharBlock &where) const { 284 return context_.FindScope(where); 285 } AnyFatalError()286 bool AnyFatalError() const { return context_.AnyFatalError(); } 287 void EmitMessages(llvm::raw_ostream &) const; 288 void DumpSymbols(llvm::raw_ostream &); 289 void DumpSymbolsSources(llvm::raw_ostream &) const; 290 291 private: 292 SemanticsContext &context_; 293 parser::Program &program_; 294 }; 295 296 // Base class for semantics checkers. 297 struct BaseChecker { EnterBaseChecker298 template <typename N> void Enter(const N &) {} LeaveBaseChecker299 template <typename N> void Leave(const N &) {} 300 }; 301 } // namespace Fortran::semantics 302 #endif 303