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