FLANG

characteristics.h
1 //===-- include/flang/Evaluate/characteristics.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 // Defines data structures to represent "characteristics" of Fortran
10 // procedures and other entities as they are specified in section 15.3
11 // of Fortran 2018.
12
13 #ifndef FORTRAN_EVALUATE_CHARACTERISTICS_H_
14 #define FORTRAN_EVALUATE_CHARACTERISTICS_H_
15
16 #include "common.h"
17 #include "expression.h"
18 #include "shape.h"
19 #include "type.h"
20 #include "flang/Common/Fortran.h"
21 #include "flang/Common/enum-set.h"
22 #include "flang/Common/idioms.h"
23 #include "flang/Common/indirection.h"
24 #include "flang/Parser/char-block.h"
25 #include "flang/Semantics/symbol.h"
26 #include <optional>
27 #include <string>
28 #include <variant>
29 #include <vector>
30
31 namespace llvm {
32 class raw_ostream;
33 }
34
35 namespace Fortran::evaluate {
36 class IntrinsicProcTable;
37 }
38 namespace Fortran::evaluate::characteristics {
39 struct Procedure;
40 }
41 extern template class Fortran::common::Indirection<
42 Fortran::evaluate::characteristics::Procedure, true>;
43
44 namespace Fortran::evaluate::characteristics {
45
46 using common::CopyableIndirection;
47
48 // Are these procedures distinguishable for a generic name?
49 bool Distinguishable(const Procedure &, const Procedure &);
50 // Are these procedures distinguishable for a generic operator or assignment?
51 bool DistinguishableOpOrAssign(const Procedure &, const Procedure &);
52
53 // Shapes of function results and dummy arguments have to have
54 // the same rank, the same deferred dimensions, and the same
55 // values for explicit dimensions when constant.
56 bool ShapesAreCompatible(const Shape &, const Shape &);
57
58 class TypeAndShape {
59 public:
60 ENUM_CLASS(
61 Attr, AssumedRank, AssumedShape, AssumedSize, DeferredShape, Coarray)
62 using Attrs = common::EnumSet<Attr, Attr_enumSize>;
63
64 explicit TypeAndShape(DynamicType t) : type_{t} { AcquireLEN(); }
65 TypeAndShape(DynamicType t, int rank) : type_{t}, shape_(rank) {
66 AcquireLEN();
67 }
68 TypeAndShape(DynamicType t, Shape &&s) : type_{t}, shape_{std::move(s)} {
69 AcquireLEN();
70 }
71 TypeAndShape(DynamicType t, std::optional<Shape> &&s) : type_{t} {
72 if (s) {
73 shape_ = std::move(*s);
74 }
75 AcquireLEN();
76 }
77 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(TypeAndShape)
78
79 bool operator==(const TypeAndShape &) const;
80 bool operator!=(const TypeAndShape &that) const { return !(*this == that); }
81 static std::optional<TypeAndShape> Characterize(
82 const semantics::Symbol &, FoldingContext &);
83 static std::optional<TypeAndShape> Characterize(
84 const semantics::ObjectEntityDetails &);
85 static std::optional<TypeAndShape> Characterize(
86 const semantics::AssocEntityDetails &, FoldingContext &);
87 static std::optional<TypeAndShape> Characterize(
88 const semantics::ProcEntityDetails &);
89 static std::optional<TypeAndShape> Characterize(
90 const semantics::ProcInterface &);
91 static std::optional<TypeAndShape> Characterize(
92 const semantics::DeclTypeSpec &);
93
94 template <typename A>
95 static std::optional<TypeAndShape> Characterize(
96 const A &x, FoldingContext &context) {
97 if (const auto *symbol{UnwrapWholeSymbolDataRef(x)}) {
98 if (auto result{Characterize(*symbol, context)}) {
99 return result;
100 }
101 }
102 if (auto type{x.GetType()}) {
103 if (auto shape{GetShape(context, x)}) {
104 TypeAndShape result{*type, std::move(*shape)};
105 if (type->category() == TypeCategory::Character) {
106 if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(x)}) {
107 if (auto length{chExpr->LEN()}) {
108 result.set_LEN(Expr<SomeInteger>{std::move(*length)});
109 }
110 }
111 }
112 return result;
113 }
114 }
115 return std::nullopt;
116 }
117
118 DynamicType type() const { return type_; }
119 TypeAndShape &set_type(DynamicType t) {
120 type_ = t;
121 return *this;
122 }
123 const std::optional<Expr<SomeInteger>> &LEN() const { return LEN_; }
124 TypeAndShape &set_LEN(Expr<SomeInteger> &&len) {
125 LEN_ = std::move(len);
126 return *this;
127 }
128 const Shape &shape() const { return shape_; }
129 const Attrs &attrs() const { return attrs_; }
130 int corank() const { return corank_; }
131
132 int Rank() const { return GetRank(shape_); }
133 bool IsCompatibleWith(parser::ContextualMessages &, const TypeAndShape &that,
134 const char *thisIs = "POINTER", const char *thatIs = "TARGET",
135 bool isElemental = false) const;
136
137 llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
138
139 private:
140 void AcquireShape(const semantics::ObjectEntityDetails &);
141 void AcquireLEN();
142
143 protected:
144 DynamicType type_;
145 std::optional<Expr<SomeInteger>> LEN_;
146 Shape shape_;
147 Attrs attrs_;
148 int corank_{0};
149 };
150
151 // 15.3.2.2
152 struct DummyDataObject {
153 ENUM_CLASS(Attr, Optional, Allocatable, Asynchronous, Contiguous, Value,
154 Volatile, Pointer, Target)
155 using Attrs = common::EnumSet<Attr, Attr_enumSize>;
156 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(DummyDataObject)
157 explicit DummyDataObject(const TypeAndShape &t) : type{t} {}
158 explicit DummyDataObject(TypeAndShape &&t) : type{std::move(t)} {}
159 explicit DummyDataObject(DynamicType t) : type{t} {}
160 bool operator==(const DummyDataObject &) const;
161 bool operator!=(const DummyDataObject &that) const {
162 return !(*this == that);
163 }
164 static std::optional<DummyDataObject> Characterize(const semantics::Symbol &);
165 bool CanBePassedViaImplicitInterface() const;
166 llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
167 TypeAndShape type;
168 std::vector<Expr<SubscriptInteger>> coshape;
169 common::Intent intent{common::Intent::Default};
170 Attrs attrs;
171 };
172
173 // 15.3.2.3
174 struct DummyProcedure {
175 ENUM_CLASS(Attr, Pointer, Optional)
176 using Attrs = common::EnumSet<Attr, Attr_enumSize>;
177 DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(DummyProcedure)
178 explicit DummyProcedure(Procedure &&);
179 bool operator==(const DummyProcedure &) const;
180 bool operator!=(const DummyProcedure &that) const { return !(*this == that); }
181 static std::optional<DummyProcedure> Characterize(
182 const semantics::Symbol &, const IntrinsicProcTable &);
183 llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
184 CopyableIndirection<Procedure> procedure;
185 common::Intent intent{common::Intent::Default};
186 Attrs attrs;
187 };
188
189 // 15.3.2.4
190 struct AlternateReturn {
191 bool operator==(const AlternateReturn &) const { return true; }
192 bool operator!=(const AlternateReturn &) const { return false; }
193 llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
194 };
195
196 // 15.3.2.1
197 struct DummyArgument {
198 DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(DummyArgument)
199 DummyArgument(std::string &&name, DummyDataObject &&x)
200 : name{std::move(name)}, u{std::move(x)} {}
201 DummyArgument(std::string &&name, DummyProcedure &&x)
202 : name{std::move(name)}, u{std::move(x)} {}
203 explicit DummyArgument(AlternateReturn &&x) : u{std::move(x)} {}
204 ~DummyArgument();
205 bool operator==(const DummyArgument &) const;
206 bool operator!=(const DummyArgument &that) const { return !(*this == that); }
207 static std::optional<DummyArgument> Characterize(
208 const semantics::Symbol &, const IntrinsicProcTable &);
209 static std::optional<DummyArgument> FromActual(
210 std::string &&, const Expr<SomeType> &, FoldingContext &);
211 bool IsOptional() const;
212 void SetOptional(bool = true);
213 bool CanBePassedViaImplicitInterface() const;
214 llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
215 // name and pass are not characteristics and so does not participate in
216 // operator== but are needed to determine if procedures are distinguishable
217 std::string name;
218 bool pass{false}; // is this the PASS argument of its procedure
219 std::variant<DummyDataObject, DummyProcedure, AlternateReturn> u;
220 };
221
222 using DummyArguments = std::vector<DummyArgument>;
223
224 // 15.3.3
225 struct FunctionResult {
226 ENUM_CLASS(Attr, Allocatable, Pointer, Contiguous)
227 using Attrs = common::EnumSet<Attr, Attr_enumSize>;
228 DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(FunctionResult)
229 explicit FunctionResult(DynamicType);
230 explicit FunctionResult(TypeAndShape &&);
231 explicit FunctionResult(Procedure &&);
232 ~FunctionResult();
233 bool operator==(const FunctionResult &) const;
234 bool operator!=(const FunctionResult &that) const { return !(*this == that); }
235 static std::optional<FunctionResult> Characterize(
236 const Symbol &, const IntrinsicProcTable &);
237
238 bool IsAssumedLengthCharacter() const;
239
240 const Procedure *IsProcedurePointer() const {
241 if (const auto *pp{std::get_if<CopyableIndirection<Procedure>>(&u)}) {
242 return &pp->value();
243 } else {
244 return nullptr;
245 }
246 }
247 const TypeAndShape *GetTypeAndShape() const {
248 return std::get_if<TypeAndShape>(&u);
249 }
250 void SetType(DynamicType t) { std::get<TypeAndShape>(u).set_type(t); }
251 bool CanBeReturnedViaImplicitInterface() const;
252
253 llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
254
255 Attrs attrs;
256 std::variant<TypeAndShape, CopyableIndirection<Procedure>> u;
257 };
258
259 // 15.3.1
260 struct Procedure {
261 ENUM_CLASS(
262 Attr, Pure, Elemental, BindC, ImplicitInterface, NullPointer, Subroutine)
263 using Attrs = common::EnumSet<Attr, Attr_enumSize>;
264 Procedure(FunctionResult &&, DummyArguments &&, Attrs);
265 Procedure(DummyArguments &&, Attrs); // for subroutines and NULL()
266 DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(Procedure)
267 ~Procedure();
268 bool operator==(const Procedure &) const;
269 bool operator!=(const Procedure &that) const { return !(*this == that); }
270
271 // Characterizes the procedure represented by a symbol, which may be an
272 // "unrestricted specific intrinsic function".
273 static std::optional<Procedure> Characterize(
274 const semantics::Symbol &, const IntrinsicProcTable &);
275 static std::optional<Procedure> Characterize(
276 const ProcedureDesignator &, const IntrinsicProcTable &);
277 static std::optional<Procedure> Characterize(
278 const ProcedureRef &, const IntrinsicProcTable &);
279
280 // At most one of these will return true.
281 // For "EXTERNAL P" with no type for or calls to P, both will be false.
282 bool IsFunction() const { return functionResult.has_value(); }
283 bool IsSubroutine() const { return attrs.test(Attr::Subroutine); }
284
285 bool IsPure() const { return attrs.test(Attr::Pure); }
286 bool IsElemental() const { return attrs.test(Attr::Elemental); }
287 bool IsBindC() const { return attrs.test(Attr::BindC); }
288 bool HasExplicitInterface() const {
289 return !attrs.test(Attr::ImplicitInterface);
290 }
291 int FindPassIndex(std::optional<parser::CharBlock>) const;
292 bool CanBeCalledViaImplicitInterface() const;
293 bool CanOverride(const Procedure &, std::optional<int> passIndex) const;
294 llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
295
296 std::optional<FunctionResult> functionResult;
297 DummyArguments dummyArguments;
298 Attrs attrs;
299
300 private:
301 Procedure() {}
302 };
303
304 } // namespace Fortran::evaluate::characteristics
305 #endif // FORTRAN_EVALUATE_CHARACTERISTICS_H_
Fortran::evaluate::Expr< SomeType >
Definition: expression.h:784
Fortran::evaluate::characteristics::AlternateReturn
Definition: characteristics.h:190
Fortran::evaluate::characteristics::Procedure
Definition: characteristics.h:260
Fortran::semantics::ObjectEntityDetails
Definition: symbol.h:160
Fortran::parser::ContextualMessages
Definition: message.h:271
Fortran::semantics::ProcInterface
Definition: type.h:373
Fortran::evaluate::characteristics::DummyArgument
Definition: characteristics.h:197
Fortran::evaluate::DynamicType
Definition: type.h:85
Fortran::semantics::DeclTypeSpec
Definition: type.h:302
Fortran::semantics::Symbol
Definition: symbol.h:479
Fortran::evaluate::characteristics::FunctionResult
Definition: characteristics.h:225
Fortran::evaluate::FoldingContext
Definition: common.h:209
Fortran::semantics::AssocEntityDetails
Definition: symbol.h:142
Fortran::evaluate::characteristics::DummyProcedure
Definition: characteristics.h:174
Fortran::evaluate::ProcedureDesignator
Definition: call.h:159
Fortran::semantics::ProcEntityDetails
Definition: symbol.h:215
Fortran::common::Indirection
Definition: indirection.h:31
Fortran::evaluate::characteristics::TypeAndShape
Definition: characteristics.h:58
Fortran::common::EnumSet< Attr, Attr_enumSize >
Fortran::evaluate::NullPointer
Definition: expression.h:771
Fortran::evaluate::ProcedureRef
Definition: call.h:190
Fortran::evaluate::Expr
Definition: common.h:207
Fortran::evaluate::characteristics::DummyDataObject
Definition: characteristics.h:152