| 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 | parser::CharBlock MakeNameFromOperator( |
| 150 | const parser::DefinedOperator::IntrinsicOperator &op, |
| 151 | SemanticsContext &context); |
| 152 | parser::CharBlock MangleSpecialFunctions(const parser::CharBlock &name); |
| 153 | std::string MangleDefinedOperator(const parser::CharBlock &name); |
| 154 | |
| 155 | } // namespace Fortran::semantics |
| 156 | #endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_ |
| 157 | |