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