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