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