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