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