FLANG

variable.h
1 //===-- include/flang/Evaluate/variable.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_EVALUATE_VARIABLE_H_
10 #define FORTRAN_EVALUATE_VARIABLE_H_
11
12 // Defines data structures to represent data access and function calls
13 // for use in expressions and assignment statements. Both copy and move
14 // semantics are supported. The representation adheres closely to the
15 // Fortran 2018 language standard (q.v.) and uses strong typing to ensure
16 // that only admissable combinations can be constructed.
17
18 #include "call.h"
19 #include "common.h"
20 #include "formatting.h"
21 #include "static-data.h"
22 #include "type.h"
23 #include "flang/Common/idioms.h"
24 #include "flang/Common/reference.h"
25 #include "flang/Common/template.h"
26 #include "flang/Parser/char-block.h"
27 #include <optional>
28 #include <variant>
29 #include <vector>
30
31 namespace llvm {
32 class raw_ostream;
33 }
34
35 namespace Fortran::semantics {
36 class Symbol;
37 }
38
39 namespace Fortran::evaluate {
40
41 using semantics::Symbol;
42 using SymbolRef = common::Reference<const Symbol>;
43 using SymbolVector = std::vector<SymbolRef>;
44
45 // Forward declarations
46 struct DataRef;
47 template <typename T> struct Variable;
48
49 // Reference a base object in memory. This can be a Fortran symbol,
50 // static data (e.g., CHARACTER literal), or compiler-created temporary.
51 struct BaseObject {
52 EVALUATE_UNION_CLASS_BOILERPLATE(BaseObject)
53 int Rank() const;
54 std::optional<Expr<SubscriptInteger>> LEN() const;
55 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
56 const Symbol *symbol() const {
57 if (const auto *result{std::get_if<SymbolRef>(&u)}) {
58 return &result->get();
59 } else {
60 return nullptr;
61 }
62 }
63 std::variant<SymbolRef, StaticDataObject::Pointer> u;
64 };
65
66 // R913 structure-component & C920: Defined to be a multi-part
67 // data-ref whose last part has no subscripts (or image-selector, although
68 // that isn't explicit in the document). Pointer and allocatable components
69 // are not explicitly indirected in this representation.
70 // Complex components (%RE, %IM) are isolated below in ComplexPart.
71 // (Type parameter inquiries look like component references but are distinct
72 // constructs and not represented by this class.)
73 class Component {
74 public:
75 CLASS_BOILERPLATE(Component)
76 Component(const DataRef &b, const Symbol &c) : base_{b}, symbol_{c} {}
77 Component(DataRef &&b, const Symbol &c) : base_{std::move(b)}, symbol_{c} {}
78 Component(common::CopyableIndirection<DataRef> &&b, const Symbol &c)
79 : base_{std::move(b)}, symbol_{c} {}
80
81 const DataRef &base() const { return base_.value(); }
82 DataRef &base() { return base_.value(); }
83 int Rank() const;
84 const Symbol &GetFirstSymbol() const;
85 const Symbol &GetLastSymbol() const { return symbol_; }
86 std::optional<Expr<SubscriptInteger>> LEN() const;
87 bool operator==(const Component &) const;
88 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
89
90 private:
91 common::CopyableIndirection<DataRef> base_;
92 SymbolRef symbol_;
93 };
94
95 // A NamedEntity is either a whole Symbol or a component in an instance
96 // of a derived type. It may be a descriptor.
97 // TODO: this is basically a symbol with an optional DataRef base;
98 // could be used to replace Component.
99 class NamedEntity {
100 public:
101 CLASS_BOILERPLATE(NamedEntity)
102 explicit NamedEntity(const Symbol &symbol) : u_{symbol} {}
103 explicit NamedEntity(Component &&c) : u_{std::move(c)} {}
104
105 bool IsSymbol() const { return std::holds_alternative<SymbolRef>(u_); }
106 const Symbol &GetFirstSymbol() const;
107 const Symbol &GetLastSymbol() const;
108 const Component &GetComponent() const { return std::get<Component>(u_); }
109 Component &GetComponent() { return std::get<Component>(u_); }
110 const Component *UnwrapComponent() const; // null if just a Symbol
111 Component *UnwrapComponent();
112
113 int Rank() const;
114 std::optional<Expr<SubscriptInteger>> LEN() const;
115 bool operator==(const NamedEntity &) const;
116 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
117
118 private:
119 std::variant<SymbolRef, Component> u_;
120 };
121
122 // R916 type-param-inquiry
123 // N.B. x%LEN for CHARACTER is rewritten in semantics to LEN(x), which is
124 // then handled via LEN() member functions in the various classes;
125 // it becomes a DescriptorInquiry with Field::Len for assumed-length
126 // CHARACTER objects.
127 // x%KIND for intrinsic types is similarly rewritten in semantics to
128 // KIND(x), which is then folded to a constant value.
129 // "Bare" type parameter references within a derived type definition do
130 // not have base objects.
131 template <int KIND> class TypeParamInquiry {
132 public:
133 using Result = Type<TypeCategory::Integer, KIND>;
134 CLASS_BOILERPLATE(TypeParamInquiry)
135 TypeParamInquiry(NamedEntity &&x, const Symbol &param)
136 : base_{std::move(x)}, parameter_{param} {}
137 TypeParamInquiry(std::optional<NamedEntity> &&x, const Symbol &param)
138 : base_{std::move(x)}, parameter_{param} {}
139
140 const std::optional<NamedEntity> &base() const { return base_; }
141 std::optional<NamedEntity> &base() { return base_; }
142 const Symbol &parameter() const { return parameter_; }
143
144 static constexpr int Rank() { return 0; } // always scalar
145 bool operator==(const TypeParamInquiry &) const;
146 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
147
148 private:
149 std::optional<NamedEntity> base_;
150 SymbolRef parameter_;
151 };
152
153 EXPAND_FOR_EACH_INTEGER_KIND(
154 TEMPLATE_INSTANTIATION, extern template class TypeParamInquiry, )
155
156 // R921 subscript-triplet
157 class Triplet {
158 public:
159 Triplet();
160 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(Triplet)
161 Triplet(std::optional<Expr<SubscriptInteger>> &&,
162 std::optional<Expr<SubscriptInteger>> &&,
163 std::optional<Expr<SubscriptInteger>> &&);
164
165 std::optional<Expr<SubscriptInteger>> lower() const;
166 Triplet &set_lower(Expr<SubscriptInteger> &&);
167 std::optional<Expr<SubscriptInteger>> upper() const;
168 Triplet &set_upper(Expr<SubscriptInteger> &&);
169 Expr<SubscriptInteger> stride() const; // N.B. result is not optional<>
170 Triplet &set_stride(Expr<SubscriptInteger> &&);
171
172 bool operator==(const Triplet &) const;
173 bool IsStrideOne() const;
174 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
175
176 private:
177 std::optional<IndirectSubscriptIntegerExpr> lower_, upper_;
178 IndirectSubscriptIntegerExpr stride_;
179 };
180
181 // R919 subscript when rank 0, R923 vector-subscript when rank 1
182 struct Subscript {
183 EVALUATE_UNION_CLASS_BOILERPLATE(Subscript)
184 explicit Subscript(Expr<SubscriptInteger> &&s)
185 : u{IndirectSubscriptIntegerExpr::Make(std::move(s))} {}
186 int Rank() const;
187 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
188 std::variant<IndirectSubscriptIntegerExpr, Triplet> u;
189 };
190
191 // R917 array-element, R918 array-section; however, the case of an
192 // array-section that is a complex-part-designator is represented here
193 // as a ComplexPart instead. C919 & C925 require that at most one set of
194 // subscripts have rank greater than 0, but that is not explicit in
195 // these types.
196 class ArrayRef {
197 public:
198 CLASS_BOILERPLATE(ArrayRef)
199 ArrayRef(const Symbol &symbol, std::vector<Subscript> &&ss)
200 : base_{symbol}, subscript_(std::move(ss)) {}
201 ArrayRef(Component &&c, std::vector<Subscript> &&ss)
202 : base_{std::move(c)}, subscript_(std::move(ss)) {}
203 ArrayRef(NamedEntity &&base, std::vector<Subscript> &&ss)
204 : base_{std::move(base)}, subscript_(std::move(ss)) {}
205
206 NamedEntity &base() { return base_; }
207 const NamedEntity &base() const { return base_; }
208 std::vector<Subscript> &subscript() { return subscript_; }
209 const std::vector<Subscript> &subscript() const { return subscript_; }
210
211 int size() const { return static_cast<int>(subscript_.size()); }
212 Subscript &at(int n) { return subscript_.at(n); }
213 const Subscript &at(int n) const { return subscript_.at(n); }
214 template <typename A> common::IfNoLvalue<Subscript &, A> emplace_back(A &&x) {
215 return subscript_.emplace_back(std::move(x));
216 }
217
218 int Rank() const;
219 const Symbol &GetFirstSymbol() const;
220 const Symbol &GetLastSymbol() const;
221 std::optional<Expr<SubscriptInteger>> LEN() const;
222 bool operator==(const ArrayRef &) const;
223 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
224
225 private:
226 NamedEntity base_;
227 std::vector<Subscript> subscript_;
228 };
229
230 // R914 coindexed-named-object
231 // R924 image-selector, R926 image-selector-spec.
232 // C824 severely limits the usage of derived types with coarray ultimate
233 // components: they can't be pointers, allocatables, arrays, coarrays, or
234 // function results. They can be components of other derived types.
235 // Although the F'2018 Standard never prohibits multiple image-selectors
236 // per se in the same data-ref or designator, nor the presence of an
237 // image-selector after a part-ref with rank, the constraints on the
238 // derived types that would have be involved make it impossible to declare
239 // an object that could be referenced in these ways (esp. C748 & C825).
240 // C930 precludes having both TEAM= and TEAM_NUMBER=.
241 // TODO C931 prohibits the use of a coindexed object as a stat-variable.
242 class CoarrayRef {
243 public:
244 CLASS_BOILERPLATE(CoarrayRef)
245 CoarrayRef(SymbolVector &&, std::vector<Subscript> &&,
246 std::vector<Expr<SubscriptInteger>> &&);
247
248 const SymbolVector &base() const { return base_; }
249 SymbolVector &base() { return base_; }
250 const std::vector<Subscript> &subscript() const { return subscript_; }
251 std::vector<Subscript> &subscript() { return subscript_; }
252 const std::vector<Expr<SubscriptInteger>> &cosubscript() const {
253 return cosubscript_;
254 }
255 std::vector<Expr<SubscriptInteger>> &cosubscript() { return cosubscript_; }
256
257 // These integral expressions for STAT= and TEAM= must be variables
258 // (i.e., Designator or pointer-valued FunctionRef).
259 std::optional<Expr<SomeInteger>> stat() const;
260 CoarrayRef &set_stat(Expr<SomeInteger> &&);
261 std::optional<Expr<SomeInteger>> team() const;
262 bool teamIsTeamNumber() const { return teamIsTeamNumber_; }
263 CoarrayRef &set_team(Expr<SomeInteger> &&, bool isTeamNumber = false);
264
265 int Rank() const;
266 const Symbol &GetFirstSymbol() const;
267 const Symbol &GetLastSymbol() const;
268 NamedEntity GetBase() const;
269 std::optional<Expr<SubscriptInteger>> LEN() const;
270 bool operator==(const CoarrayRef &) const;
271 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
272
273 private:
274 SymbolVector base_;
275 std::vector<Subscript> subscript_;
276 std::vector<Expr<SubscriptInteger>> cosubscript_;
277 std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_;
278 bool teamIsTeamNumber_{false}; // false: TEAM=, true: TEAM_NUMBER=
279 };
280
281 // R911 data-ref is defined syntactically as a series of part-refs, which
282 // would be far too expressive if the constraints were ignored. Here, the
283 // possible outcomes are spelled out. Note that a data-ref cannot include
284 // a terminal substring range or complex component designator; use
285 // R901 designator for that.
286 struct DataRef {
287 EVALUATE_UNION_CLASS_BOILERPLATE(DataRef)
288 int Rank() const;
289 const Symbol &GetFirstSymbol() const;
290 const Symbol &GetLastSymbol() const;
291 std::optional<Expr<SubscriptInteger>> LEN() const;
292 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
293
294 std::variant<SymbolRef, Component, ArrayRef, CoarrayRef> u;
295 };
296
297 // R908 substring, R909 parent-string, R910 substring-range.
298 // The base object of a substring can be a literal.
299 // In the F2018 standard, substrings of array sections are parsed as
300 // variants of sections instead.
301 class Substring {
302 using Parent = std::variant<DataRef, StaticDataObject::Pointer>;
303
304 public:
305 CLASS_BOILERPLATE(Substring)
306 Substring(DataRef &&parent, std::optional<Expr<SubscriptInteger>> &&lower,
307 std::optional<Expr<SubscriptInteger>> &&upper)
308 : parent_{std::move(parent)} {
309 SetBounds(lower, upper);
310 }
311 Substring(StaticDataObject::Pointer &&parent,
312 std::optional<Expr<SubscriptInteger>> &&lower,
313 std::optional<Expr<SubscriptInteger>> &&upper)
314 : parent_{std::move(parent)} {
315 SetBounds(lower, upper);
316 }
317
318 Expr<SubscriptInteger> lower() const;
319 Substring &set_lower(Expr<SubscriptInteger> &&);
320 std::optional<Expr<SubscriptInteger>> upper() const;
321 Substring &set_upper(Expr<SubscriptInteger> &&);
322 const Parent &parent() const { return parent_; }
323 Parent &parent() { return parent_; }
324
325 int Rank() const;
326 template <typename A> const A *GetParentIf() const {
327 return std::get_if<A>(&parent_);
328 }
329 BaseObject GetBaseObject() const;
330 const Symbol *GetLastSymbol() const;
331 std::optional<Expr<SubscriptInteger>> LEN() const;
332 bool operator==(const Substring &) const;
333 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
334
335 std::optional<Expr<SomeCharacter>> Fold(FoldingContext &);
336
337 private:
338 void SetBounds(std::optional<Expr<SubscriptInteger>> &,
339 std::optional<Expr<SubscriptInteger>> &);
340 Parent parent_;
341 std::optional<IndirectSubscriptIntegerExpr> lower_, upper_;
342 };
343
344 // R915 complex-part-designator
345 // In the F2018 standard, complex parts of array sections are parsed as
346 // variants of sections instead.
347 class ComplexPart {
348 public:
349 ENUM_CLASS(Part, RE, IM)
350 CLASS_BOILERPLATE(ComplexPart)
351 ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {}
352 const DataRef &complex() const { return complex_; }
353 Part part() const { return part_; }
354 int Rank() const;
355 const Symbol &GetFirstSymbol() const { return complex_.GetFirstSymbol(); }
356 const Symbol &GetLastSymbol() const { return complex_.GetLastSymbol(); }
357 bool operator==(const ComplexPart &) const;
358 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
359
360 private:
361 DataRef complex_;
362 Part part_;
363 };
364
365 // R901 designator is the most general data reference object, apart from
366 // calls to pointer-valued functions. Its variant holds everything that
367 // a DataRef can, and possibly also a substring reference or a
368 // complex component (%RE/%IM) reference.
369 template <typename T> class Designator {
370 using DataRefs = std::decay_t<decltype(DataRef::u)>;
371 using MaybeSubstring =
372 std::conditional_t<T::category == TypeCategory::Character,
373 std::variant<Substring>, std::variant<>>;
374 using MaybeComplexPart = std::conditional_t<T::category == TypeCategory::Real,
375 std::variant<ComplexPart>, std::variant<>>;
376 using Variant =
377 common::CombineVariants<DataRefs, MaybeSubstring, MaybeComplexPart>;
378
379 public:
380 using Result = T;
381 static_assert(
382 IsSpecificIntrinsicType<Result> || std::is_same_v<Result, SomeDerived>);
383 EVALUATE_UNION_CLASS_BOILERPLATE(Designator)
384 Designator(const DataRef &that) : u{common::CopyVariant<Variant>(that.u)} {}
385 Designator(DataRef &&that)
386 : u{common::MoveVariant<Variant>(std::move(that.u))} {}
387
388 std::optional<DynamicType> GetType() const;
389 int Rank() const;
390 BaseObject GetBaseObject() const;
391 const Symbol *GetLastSymbol() const;
392 std::optional<Expr<SubscriptInteger>> LEN() const;
393 llvm::raw_ostream &AsFortran(llvm::raw_ostream &o) const;
394
395 Variant u;
396 };
397
398 FOR_EACH_CHARACTER_KIND(extern template class Designator, )
399
400 class DescriptorInquiry {
401 public:
402 using Result = SubscriptInteger;
403 ENUM_CLASS(Field, LowerBound, Extent, Stride, Rank, Len)
404
405 CLASS_BOILERPLATE(DescriptorInquiry)
406 DescriptorInquiry(const NamedEntity &, Field, int = 0);
407 DescriptorInquiry(NamedEntity &&, Field, int = 0);
408
409 NamedEntity &base() { return base_; }
410 const NamedEntity &base() const { return base_; }
411 Field field() const { return field_; }
412 int dimension() const { return dimension_; }
413
414 static constexpr int Rank() { return 0; } // always scalar
415 bool operator==(const DescriptorInquiry &) const;
416 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
417
418 private:
419 NamedEntity base_;
420 Field field_;
421 int dimension_{0}; // zero-based
422 };
423
424 #define INSTANTIATE_VARIABLE_TEMPLATES \
425 EXPAND_FOR_EACH_INTEGER_KIND( \
426 TEMPLATE_INSTANTIATION, template class TypeParamInquiry, ) \
427 FOR_EACH_SPECIFIC_TYPE(template class Designator, )
428 } // namespace Fortran::evaluate
429 #endif // FORTRAN_EVALUATE_VARIABLE_H_
Fortran::evaluate::CoarrayRef
Definition: variable.h:242
Fortran::evaluate::Subscript
Definition: variable.h:182
Fortran::evaluate::Variable
Definition: variable.h:47
Fortran::evaluate::Substring
Definition: variable.h:301
Fortran::evaluate::Type< TypeCategory::Integer, KIND >
Definition: type.h:231
Fortran::evaluate::Type
Definition: type.h:48
Fortran::evaluate::Component
Definition: variable.h:73
Fortran::semantics::Symbol
Definition: symbol.h:479
Fortran::evaluate::ComplexPart
Definition: variable.h:347
Fortran::evaluate::DataRef
Definition: variable.h:286
Fortran::evaluate::BaseObject
Definition: variable.h:51
Fortran::evaluate::ArrayRef
Definition: variable.h:196
Fortran::evaluate::FoldingContext
Definition: common.h:209
Fortran::common::Reference< const Symbol >
Fortran::evaluate::DescriptorInquiry
Definition: variable.h:400
Fortran::common::Indirection< A, true >
Definition: indirection.h:72
Fortran::evaluate::Designator
Definition: variable.h:369
Fortran::evaluate::NamedEntity
Definition: variable.h:99
Fortran::evaluate::TypeParamInquiry
Definition: variable.h:131
Fortran::evaluate::Expr
Definition: common.h:207