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