1 //===-- lib/Semantics/resolve-names-utils.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_RESOLVE_NAMES_UTILS_H_ 10 #define FORTRAN_SEMANTICS_RESOLVE_NAMES_UTILS_H_ 11 12 // Utility functions and class for use in resolve-names.cpp. 13 14 #include "flang/Evaluate/fold.h" 15 #include "flang/Parser/message.h" 16 #include "flang/Parser/tools.h" 17 #include "flang/Semantics/expression.h" 18 #include "flang/Semantics/scope.h" 19 #include "flang/Semantics/semantics.h" 20 #include "flang/Semantics/symbol.h" 21 #include "flang/Semantics/type.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include <forward_list> 24 25 namespace Fortran::parser { 26 class CharBlock; 27 struct ArraySpec; 28 struct CoarraySpec; 29 struct ComponentArraySpec; 30 struct DataRef; 31 struct DefinedOpName; 32 struct Designator; 33 struct Expr; 34 struct GenericSpec; 35 struct Name; 36 } // namespace Fortran::parser 37 38 namespace Fortran::semantics { 39 40 using SourceName = parser::CharBlock; 41 class SemanticsContext; 42 43 // Record that a Name has been resolved to a Symbol 44 Symbol &Resolve(const parser::Name &, Symbol &); 45 Symbol *Resolve(const parser::Name &, Symbol *); 46 47 // Create a copy of msg with a new severity. 48 parser::MessageFixedText WithSeverity( 49 const parser::MessageFixedText &msg, parser::Severity); 50 51 bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &); 52 bool IsLogicalConstant(const SemanticsContext &, const SourceName &); 53 54 template <typename T> 55 MaybeIntExpr EvaluateIntExpr(SemanticsContext &context, const T &expr) { 56 if (MaybeExpr maybeExpr{ 57 Fold(context.foldingContext(), AnalyzeExpr(context, expr))}) { 58 if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) { 59 return std::move(*intExpr); 60 } 61 } 62 return std::nullopt; 63 } 64 65 template <typename T> 66 std::optional<std::int64_t> EvaluateInt64( 67 SemanticsContext &context, const T &expr) { 68 return evaluate::ToInt64(EvaluateIntExpr(context, expr)); 69 } 70 71 // Analyze a generic-spec and generate a symbol name and GenericKind for it. 72 class GenericSpecInfo { 73 public: 74 explicit GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); } 75 explicit GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); } 76 77 GenericKind kind() const { return kind_; } 78 const SourceName &symbolName() const { return symbolName_.value(); } 79 // Set the GenericKind in this symbol and resolve the corresponding 80 // name if there is one 81 void Resolve(Symbol *) const; 82 friend llvm::raw_ostream &operator<<( 83 llvm::raw_ostream &, const GenericSpecInfo &); 84 85 private: 86 void Analyze(const parser::DefinedOpName &); 87 void Analyze(const parser::GenericSpec &); 88 89 GenericKind kind_; 90 const parser::Name *parseName_{nullptr}; 91 std::optional<SourceName> symbolName_; 92 }; 93 94 // Analyze a parser::ArraySpec or parser::CoarraySpec 95 ArraySpec AnalyzeArraySpec(SemanticsContext &, const parser::ArraySpec &); 96 ArraySpec AnalyzeArraySpec( 97 SemanticsContext &, const parser::ComponentArraySpec &); 98 ArraySpec AnalyzeDeferredShapeSpecList( 99 SemanticsContext &, const parser::DeferredShapeSpecList &); 100 ArraySpec AnalyzeCoarraySpec( 101 SemanticsContext &context, const parser::CoarraySpec &); 102 103 // Perform consistency checks on equivalence sets 104 class EquivalenceSets { 105 public: 106 EquivalenceSets(SemanticsContext &context) : context_{context} {} 107 std::vector<EquivalenceSet> &sets() { return sets_; }; 108 // Resolve this designator and add to the current equivalence set 109 void AddToSet(const parser::Designator &); 110 // Finish the current equivalence set: determine if it overlaps 111 // with any of the others and perform necessary merges if it does. 112 void FinishSet(const parser::CharBlock &); 113 114 private: 115 bool CheckCanEquivalence( 116 const parser::CharBlock &, const Symbol &, const Symbol &); 117 void MergeInto(const parser::CharBlock &, EquivalenceSet &, std::size_t); 118 const EquivalenceObject *Find(const EquivalenceSet &, const Symbol &); 119 bool CheckDesignator(const parser::Designator &); 120 bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &); 121 bool CheckObject(const parser::Name &); 122 bool CheckArrayBound(const parser::Expr &); 123 bool CheckSubstringBound(const parser::Expr &, bool); 124 bool IsCharacterSequenceType(const DeclTypeSpec *); 125 bool IsDefaultKindNumericType(const IntrinsicTypeSpec &); 126 bool IsDefaultNumericSequenceType(const DeclTypeSpec *); 127 static bool IsAnyNumericSequenceType(const DeclTypeSpec *); 128 static bool IsSequenceType( 129 const DeclTypeSpec *, std::function<bool(const IntrinsicTypeSpec &)>); 130 131 SemanticsContext &context_; 132 std::vector<EquivalenceSet> sets_; // all equivalence sets in this scope 133 // Map object to index of set it is in 134 std::map<EquivalenceObject, std::size_t> objectToSet_; 135 EquivalenceSet currSet_; // equivalence set currently being constructed 136 struct { 137 Symbol *symbol{nullptr}; 138 std::vector<ConstantSubscript> subscripts; 139 std::optional<ConstantSubscript> substringStart; 140 } currObject_; // equivalence object currently being constructed 141 }; 142 143 // Duplicates a subprogram's dummy arguments and result, if any, and 144 // maps all of the symbols in their expressions. 145 struct SymbolAndTypeMappings; 146 void MapSubprogramToNewSymbols(const Symbol &oldSymbol, Symbol &newSymbol, 147 Scope &newScope, SymbolAndTypeMappings * = nullptr); 148 149 } // namespace Fortran::semantics 150 #endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_ 151