• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <forward_list>
23 
24 namespace Fortran::parser {
25 class CharBlock;
26 struct ArraySpec;
27 struct CoarraySpec;
28 struct ComponentArraySpec;
29 struct DataRef;
30 struct DefinedOpName;
31 struct Designator;
32 struct Expr;
33 struct GenericSpec;
34 struct Name;
35 } // namespace Fortran::parser
36 
37 namespace Fortran::semantics {
38 
39 using SourceName = parser::CharBlock;
40 class SemanticsContext;
41 
42 // Record that a Name has been resolved to a Symbol
43 Symbol &Resolve(const parser::Name &, Symbol &);
44 Symbol *Resolve(const parser::Name &, Symbol *);
45 
46 // Create a copy of msg with a new isFatal value.
47 parser::MessageFixedText WithIsFatal(
48     const parser::MessageFixedText &msg, bool isFatal);
49 
50 bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &);
51 bool IsLogicalConstant(const SemanticsContext &, const SourceName &);
52 
53 template <typename T>
EvaluateIntExpr(SemanticsContext & context,const T & expr)54 MaybeIntExpr EvaluateIntExpr(SemanticsContext &context, const T &expr) {
55   if (MaybeExpr maybeExpr{
56           Fold(context.foldingContext(), AnalyzeExpr(context, expr))}) {
57     if (auto *intExpr{evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) {
58       return std::move(*intExpr);
59     }
60   }
61   return std::nullopt;
62 }
63 
64 template <typename T>
EvaluateInt64(SemanticsContext & context,const T & expr)65 std::optional<std::int64_t> EvaluateInt64(
66     SemanticsContext &context, const T &expr) {
67   return evaluate::ToInt64(EvaluateIntExpr(context, expr));
68 }
69 
70 // Analyze a generic-spec and generate a symbol name and GenericKind for it.
71 class GenericSpecInfo {
72 public:
GenericSpecInfo(const parser::DefinedOpName & x)73   GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
GenericSpecInfo(const parser::GenericSpec & x)74   GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
75 
kind()76   GenericKind kind() const { return kind_; }
symbolName()77   const SourceName &symbolName() const { return symbolName_.value(); }
78   // Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and
79   // `operator(==)`). GetAllNames() returns them all, including symbolName.
80   std::forward_list<std::string> GetAllNames(SemanticsContext &) const;
81   // Set the GenericKind in this symbol and resolve the corresponding
82   // name if there is one
83   void Resolve(Symbol *) const;
84   Symbol *FindInScope(SemanticsContext &, const Scope &) const;
85 
86 private:
87   GenericKind kind_;
88   const parser::Name *parseName_{nullptr};
89   std::optional<SourceName> symbolName_;
90 
91   void Analyze(const parser::DefinedOpName &);
92   void Analyze(const parser::GenericSpec &);
93 };
94 
95 // Analyze a parser::ArraySpec or parser::CoarraySpec
96 ArraySpec AnalyzeArraySpec(SemanticsContext &, const parser::ArraySpec &);
97 ArraySpec AnalyzeArraySpec(
98     SemanticsContext &, const parser::ComponentArraySpec &);
99 ArraySpec AnalyzeCoarraySpec(
100     SemanticsContext &context, const parser::CoarraySpec &);
101 
102 // Perform consistency checks on equivalence sets
103 class EquivalenceSets {
104 public:
EquivalenceSets(SemanticsContext & context)105   EquivalenceSets(SemanticsContext &context) : context_{context} {}
sets()106   std::vector<EquivalenceSet> &sets() { return sets_; };
107   // Resolve this designator and add to the current equivalence set
108   void AddToSet(const parser::Designator &);
109   // Finish the current equivalence set: determine if it overlaps
110   // with any of the others and perform necessary merges if it does.
111   void FinishSet(const parser::CharBlock &);
112 
113 private:
114   bool CheckCanEquivalence(
115       const parser::CharBlock &, const Symbol &, const Symbol &);
116   void MergeInto(const parser::CharBlock &, EquivalenceSet &, std::size_t);
117   const EquivalenceObject *Find(const EquivalenceSet &, const Symbol &);
118   bool CheckDesignator(const parser::Designator &);
119   bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &);
120   bool CheckObject(const parser::Name &);
121   bool CheckArrayBound(const parser::Expr &);
122   bool CheckSubstringBound(const parser::Expr &, bool);
123   bool IsCharacterSequenceType(const DeclTypeSpec *);
124   bool IsDefaultKindNumericType(const IntrinsicTypeSpec &);
125   bool IsNumericSequenceType(const DeclTypeSpec *);
126   bool IsSequenceType(
127       const DeclTypeSpec *, std::function<bool(const IntrinsicTypeSpec &)>);
128 
129   SemanticsContext &context_;
130   std::vector<EquivalenceSet> sets_; // all equivalence sets in this scope
131   // Map object to index of set it is in
132   std::map<EquivalenceObject, std::size_t> objectToSet_;
133   EquivalenceSet currSet_; // equivalence set currently being constructed
134   struct {
135     Symbol *symbol{nullptr};
136     std::vector<ConstantSubscript> subscripts;
137     std::optional<ConstantSubscript> substringStart;
138   } currObject_; // equivalence object currently being constructed
139 };
140 
141 } // namespace Fortran::semantics
142 #endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
143