FLANG
resolve-names-utils.h
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
24namespace Fortran::parser {
25class CharBlock;
26struct ArraySpec;
27struct CoarraySpec;
29struct DataRef;
30struct DefinedOpName;
31struct Designator;
32struct Expr;
33struct GenericSpec;
34struct Name;
35} // namespace Fortran::parser
36
37namespace Fortran::semantics {
38
39using SourceName = parser::CharBlock;
41
42// Record that a Name has been resolved to a Symbol
43Symbol &Resolve(const parser::Name &, Symbol &);
44Symbol *Resolve(const parser::Name &, Symbol *);
45
46// Create a copy of msg with a new severity.
47parser::MessageFixedText WithSeverity(
48 const parser::MessageFixedText &msg, parser::Severity);
49
50bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &);
51bool IsLogicalConstant(const SemanticsContext &, const SourceName &);
52
53template <typename T>
54MaybeIntExpr 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
64template <typename T>
65std::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.
71class GenericSpecInfo {
72public:
73 explicit GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
74 explicit GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
75
76 GenericKind kind() const { return kind_; }
77 const SourceName &symbolName() const { return symbolName_.value(); }
78 // Set the GenericKind in this symbol and resolve the corresponding
79 // name if there is one
80 void Resolve(Symbol *) const;
81 friend llvm::raw_ostream &operator<<(
82 llvm::raw_ostream &, const GenericSpecInfo &);
83
84private:
85 void Analyze(const parser::DefinedOpName &);
86 void Analyze(const parser::GenericSpec &);
87
88 GenericKind kind_;
89 const parser::Name *parseName_{nullptr};
90 std::optional<SourceName> symbolName_;
91};
92
93// Analyze a parser::ArraySpec or parser::CoarraySpec
94// A zero-size explicit-shape bounds array (F2023) declares a scalar; its
95// bounds are dropped from the shape but are still specification expressions,
96// appended to droppedBoundsToCheck so the caller can validate them during
97// declaration checking
98ArraySpec AnalyzeArraySpec(SemanticsContext &, const parser::ArraySpec &,
99 std::vector<Bound> &droppedBoundsToCheck);
100ArraySpec AnalyzeArraySpec(
102ArraySpec AnalyzeDeferredShapeSpecList(
103 SemanticsContext &, const parser::DeferredShapeSpecList &);
104ArraySpec AnalyzeCoarraySpec(
105 SemanticsContext &context, const parser::CoarraySpec &);
106
107// Perform consistency checks on equivalence sets
108class EquivalenceSets {
109public:
110 EquivalenceSets(SemanticsContext &context) : context_{context} {}
111 std::vector<EquivalenceSet> &sets() { return sets_; };
112 // Resolve this designator and add to the current equivalence set
113 void AddToSet(const parser::Designator &);
114 // Finish the current equivalence set: determine if it overlaps
115 // with any of the others and perform necessary merges if it does.
116 void FinishSet(const parser::CharBlock &);
117
118private:
119 bool CheckCanEquivalence(
120 const parser::CharBlock &, const Symbol &, const Symbol &);
121 void MergeInto(const parser::CharBlock &, EquivalenceSet &, std::size_t);
122 const EquivalenceObject *Find(const EquivalenceSet &, const Symbol &);
123 bool CheckDesignator(const parser::Designator &);
124 bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &);
125 bool CheckObject(const parser::Name &);
126 bool CheckArrayBound(const parser::Expr &);
127 bool CheckSubstringBound(const parser::Expr &, bool);
128 bool IsCharacterSequenceType(const DeclTypeSpec *);
129 bool IsDefaultKindNumericType(const IntrinsicTypeSpec &);
130 bool IsDefaultNumericSequenceType(const DeclTypeSpec *);
131 static bool IsAnyNumericSequenceType(const DeclTypeSpec *);
132 static bool IsSequenceType(
133 const DeclTypeSpec *, std::function<bool(const IntrinsicTypeSpec &)>);
134
135 SemanticsContext &context_;
136 std::vector<EquivalenceSet> sets_; // all equivalence sets in this scope
137 // Map object to index of set it is in
138 std::map<EquivalenceObject, std::size_t> objectToSet_;
139 EquivalenceSet currSet_; // equivalence set currently being constructed
140 struct {
141 Symbol *symbol{nullptr};
142 std::vector<ConstantSubscript> subscripts;
143 std::optional<ConstantSubscript> substringStart;
144 } currObject_; // equivalence object currently being constructed
145};
146
147// Duplicates a subprogram's dummy arguments and result, if any, and
148// maps all of the symbols in their expressions.
150void MapSubprogramToNewSymbols(const Symbol &oldSymbol, Symbol &newSymbol,
151 Scope &newScope, SymbolAndTypeMappings * = nullptr);
152
153parser::CharBlock MakeNameFromOperator(
154 const parser::DefinedOperator::IntrinsicOperator &op,
155 SemanticsContext &context);
156parser::CharBlock MangleSpecialFunctions(const parser::CharBlock &name);
157std::string MangleDefinedOperator(const parser::CharBlock &name);
158
159// Map a mangled declare reduction name (e.g., "op.+", "op.combine.",
160// "op.max") back to the Fortran identifier used as the scope key for the
161// corresponding operator or procedure (e.g., "operator(+)", ".combine.",
162// "max"). Non-mangled names (procedure designators) are returned as-is.
163std::string GetReductionFortranId(const parser::CharBlock &mangledName);
164
165} // namespace Fortran::semantics
166#endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
Definition char-block.h:26
Definition scope.h:68
Definition semantics.h:67
Definition symbol.h:907
Definition check-expression.h:19
Definition parse-tree.h:1373
Definition parse-tree.h:977
Definition parse-tree.h:988
Definition parse-tree.h:1850
Definition parse-tree.h:1889
Definition parse-tree.h:1737
Definition parse-tree.h:3076
Definition parse-tree.h:591
Definition type.h:239
Definition symbol.h:757
Definition resolve-names-utils.cpp:998