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 ¶m) 136 : base_{std::move(x)}, parameter_{param} {} TypeParamInquiry(std::optional<NamedEntity> && x,const Symbol & param)137 TypeParamInquiry(std::optional<NamedEntity> &&x, const Symbol ¶m) 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 ¶meter() 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