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 int Corank() const; 55 std::optional<Expr<SubscriptInteger>> LEN() const; 56 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 57 const Symbol *symbol() const { 58 if (const auto *result{std::get_if<SymbolRef>(&u)}) { 59 return &result->get(); 60 } else { 61 return nullptr; 62 } 63 } 64 std::variant<SymbolRef, StaticDataObject::Pointer> u; 65 }; 66 67 // R913 structure-component & C920: Defined to be a multi-part 68 // data-ref whose last part has no subscripts (or image-selector, although 69 // that isn't explicit in the document). Pointer and allocatable components 70 // are not explicitly indirected in this representation. 71 // Complex components (%RE, %IM) are isolated below in ComplexPart. 72 // (Type parameter inquiries look like component references but are distinct 73 // constructs and not represented by this class.) 74 class Component { 75 public: 76 CLASS_BOILERPLATE(Component) 77 Component(const DataRef &b, const Symbol &c) : base_{b}, symbol_{c} {} 78 Component(DataRef &&b, const Symbol &c) : base_{std::move(b)}, symbol_{c} {} 79 Component(common::CopyableIndirection<DataRef> &&b, const Symbol &c) 80 : base_{std::move(b)}, symbol_{c} {} 81 82 const DataRef &base() const { return base_.value(); } 83 DataRef &base() { return base_.value(); } 84 const SymbolRef &symbol() const { return symbol_; } 85 SymbolRef &symbol() { return symbol_; } 86 87 int Rank() const; 88 int Corank() const; 89 const Symbol &GetFirstSymbol() const; 90 const Symbol &GetLastSymbol() const { return symbol_; } 91 std::optional<Expr<SubscriptInteger>> LEN() const; 92 bool operator==(const Component &) const; 93 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 94 95 private: 96 common::CopyableIndirection<DataRef> base_; 97 SymbolRef symbol_; 98 }; 99 100 // A NamedEntity is either a whole Symbol or a component in an instance 101 // of a derived type. It may be a descriptor. 102 // TODO: this is basically a symbol with an optional DataRef base; 103 // could be used to replace Component. 104 class NamedEntity { 105 public: 106 CLASS_BOILERPLATE(NamedEntity) 107 explicit NamedEntity(const Symbol &symbol) : u_{symbol} {} 108 explicit NamedEntity(Component &&c) : u_{std::move(c)} {} 109 110 bool IsSymbol() const { return std::holds_alternative<SymbolRef>(u_); } 111 const Symbol &GetFirstSymbol() const; 112 const Symbol &GetLastSymbol() const; 113 const Component &GetComponent() const { return std::get<Component>(u_); } 114 Component &GetComponent() { return std::get<Component>(u_); } 115 const SymbolRef *UnwrapSymbolRef() const; // null if a Component 116 SymbolRef *UnwrapSymbolRef(); 117 const Component *UnwrapComponent() const; // null if not a Component 118 Component *UnwrapComponent(); 119 120 int Rank() const; 121 int Corank() const; 122 std::optional<Expr<SubscriptInteger>> LEN() const; 123 bool operator==(const NamedEntity &) const; 124 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 125 126 private: 127 std::variant<SymbolRef, Component> u_; 128 }; 129 130 // R916 type-param-inquiry 131 // N.B. x%LEN for CHARACTER is rewritten in semantics to LEN(x), which is 132 // then handled via LEN() member functions in the various classes; 133 // it becomes a DescriptorInquiry with Field::Len for assumed-length 134 // CHARACTER objects. 135 // x%KIND for intrinsic types is similarly rewritten in semantics to 136 // KIND(x), which is then folded to a constant value. 137 // "Bare" type parameter references within a derived type definition do 138 // not have base objects. 139 class TypeParamInquiry { 140 public: 141 using Result = SubscriptInteger; 142 CLASS_BOILERPLATE(TypeParamInquiry) 143 TypeParamInquiry(NamedEntity &&x, const Symbol ¶m) 144 : base_{std::move(x)}, parameter_{param} {} 145 TypeParamInquiry(std::optional<NamedEntity> &&x, const Symbol ¶m) 146 : base_{std::move(x)}, parameter_{param} {} 147 148 const std::optional<NamedEntity> &base() const { return base_; } 149 std::optional<NamedEntity> &base() { return base_; } 150 const Symbol ¶meter() const { return parameter_; } 151 152 static constexpr int Rank() { return 0; } // always scalar 153 static constexpr int Corank() { return 0; } 154 bool operator==(const TypeParamInquiry &) const; 155 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 156 157 private: 158 std::optional<NamedEntity> base_; 159 SymbolRef parameter_; 160 }; 161 162 // R921 subscript-triplet 163 class Triplet { 164 public: 165 Triplet(); 166 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(Triplet) 167 Triplet(std::optional<Expr<SubscriptInteger>> &&, 168 std::optional<Expr<SubscriptInteger>> &&, 169 std::optional<Expr<SubscriptInteger>> &&); 170 171 std::optional<Expr<SubscriptInteger>> lower() const; 172 const Expr<SubscriptInteger> *GetLower() const { 173 return lower_.has_value() ? &lower_->value() : nullptr; 174 } 175 Triplet &set_lower(Expr<SubscriptInteger> &&); 176 std::optional<Expr<SubscriptInteger>> upper() const; 177 const Expr<SubscriptInteger> *GetUpper() const { 178 return upper_.has_value() ? &upper_->value() : nullptr; 179 } 180 Triplet &set_upper(Expr<SubscriptInteger> &&); 181 Expr<SubscriptInteger> stride() const; // N.B. result is not optional<> 182 const Expr<SubscriptInteger> &GetStride() const { return stride_.value(); } 183 Triplet &set_stride(Expr<SubscriptInteger> &&); 184 185 bool operator==(const Triplet &) const; 186 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 187 188 private: 189 std::optional<IndirectSubscriptIntegerExpr> lower_, upper_; 190 IndirectSubscriptIntegerExpr stride_; 191 }; 192 193 // R919 subscript when rank 0, R923 vector-subscript when rank 1 194 struct Subscript { 195 EVALUATE_UNION_CLASS_BOILERPLATE(Subscript) 196 explicit Subscript(Expr<SubscriptInteger> &&s) 197 : u{IndirectSubscriptIntegerExpr::Make(std::move(s))} {} 198 int Rank() const; 199 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 200 std::variant<IndirectSubscriptIntegerExpr, Triplet> u; 201 }; 202 203 // R917 array-element, R918 array-section; however, the case of an 204 // array-section that is a complex-part-designator is represented here 205 // as a ComplexPart instead. C919 & C925 require that at most one set of 206 // subscripts have rank greater than 0, but that is not explicit in 207 // these types. 208 class ArrayRef { 209 public: 210 CLASS_BOILERPLATE(ArrayRef) 211 ArrayRef(const Symbol &symbol, std::vector<Subscript> &&ss) 212 : base_{symbol}, subscript_(std::move(ss)) {} 213 ArrayRef(Component &&c, std::vector<Subscript> &&ss) 214 : base_{std::move(c)}, subscript_(std::move(ss)) {} 215 ArrayRef(NamedEntity &&base, std::vector<Subscript> &&ss) 216 : base_{std::move(base)}, subscript_(std::move(ss)) {} 217 218 NamedEntity &base() { return base_; } 219 const NamedEntity &base() const { return base_; } 220 std::vector<Subscript> &subscript() { return subscript_; } 221 const std::vector<Subscript> &subscript() const { return subscript_; } 222 223 int size() const { return static_cast<int>(subscript_.size()); } 224 Subscript &at(int n) { return subscript_.at(n); } 225 const Subscript &at(int n) const { return subscript_.at(n); } 226 template <typename A> common::IfNoLvalue<Subscript &, A> emplace_back(A &&x) { 227 return subscript_.emplace_back(std::move(x)); 228 } 229 230 int Rank() const; 231 int Corank() const; 232 const Symbol &GetFirstSymbol() const; 233 const Symbol &GetLastSymbol() const; 234 std::optional<Expr<SubscriptInteger>> LEN() const; 235 bool operator==(const ArrayRef &) const; 236 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 237 238 private: 239 NamedEntity base_; 240 std::vector<Subscript> subscript_; 241 }; 242 243 // R914 coindexed-named-object 244 // R924 image-selector, R926 image-selector-spec. 245 // C825 severely limits the usage of derived types with coarray ultimate 246 // components: they can't be pointers, allocatables, arrays, coarrays, or 247 // function results. They can be components of other derived types. 248 // Although the F'2018 Standard never prohibits multiple image-selectors 249 // per se in the same data-ref or designator, nor the presence of an 250 // image-selector after a part-ref with rank, the constraints on the 251 // derived types that would have be involved make it impossible to declare 252 // an object that could be referenced in these ways (esp. C748 & C825). 253 // C930 precludes having both TEAM= and TEAM_NUMBER=. 254 // TODO C931 prohibits the use of a coindexed object as a stat-variable. 255 class CoarrayRef { 256 public: 257 CLASS_BOILERPLATE(CoarrayRef) 258 CoarrayRef(SymbolVector &&, std::vector<Subscript> &&, 259 std::vector<Expr<SubscriptInteger>> &&); 260 261 const SymbolVector &base() const { return base_; } 262 SymbolVector &base() { return base_; } 263 const std::vector<Subscript> &subscript() const { return subscript_; } 264 std::vector<Subscript> &subscript() { return subscript_; } 265 const std::vector<Expr<SubscriptInteger>> &cosubscript() const { 266 return cosubscript_; 267 } 268 std::vector<Expr<SubscriptInteger>> &cosubscript() { return cosubscript_; } 269 270 // These integral expressions for STAT= and TEAM= must be variables 271 // (i.e., Designator or pointer-valued FunctionRef). 272 std::optional<Expr<SomeInteger>> stat() const; 273 CoarrayRef &set_stat(Expr<SomeInteger> &&); 274 std::optional<Expr<SomeInteger>> team() const; 275 bool teamIsTeamNumber() const { return teamIsTeamNumber_; } 276 CoarrayRef &set_team(Expr<SomeInteger> &&, bool isTeamNumber = false); 277 278 int Rank() const; 279 int Corank() const { return 0; } 280 const Symbol &GetFirstSymbol() const; 281 const Symbol &GetLastSymbol() const; 282 NamedEntity GetBase() const; 283 std::optional<Expr<SubscriptInteger>> LEN() const; 284 bool operator==(const CoarrayRef &) const; 285 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 286 287 private: 288 SymbolVector base_; 289 std::vector<Subscript> subscript_; 290 std::vector<Expr<SubscriptInteger>> cosubscript_; 291 std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_; 292 bool teamIsTeamNumber_{false}; // false: TEAM=, true: TEAM_NUMBER= 293 }; 294 295 // R911 data-ref is defined syntactically as a series of part-refs, which 296 // would be far too expressive if the constraints were ignored. Here, the 297 // possible outcomes are spelled out. Note that a data-ref cannot include 298 // a terminal substring range or complex component designator; use 299 // R901 designator for that. 300 struct DataRef { 301 EVALUATE_UNION_CLASS_BOILERPLATE(DataRef) 302 int Rank() const; 303 int Corank() const; 304 const Symbol &GetFirstSymbol() const; 305 const Symbol &GetLastSymbol() const; 306 std::optional<Expr<SubscriptInteger>> LEN() const; 307 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 308 309 std::variant<SymbolRef, Component, ArrayRef, CoarrayRef> u; 310 }; 311 312 // R908 substring, R909 parent-string, R910 substring-range. 313 // The base object of a substring can be a literal. 314 // In the F2018 standard, substrings of array sections are parsed as 315 // variants of sections instead. 316 class Substring { 317 using Parent = std::variant<DataRef, StaticDataObject::Pointer>; 318 319 public: 320 CLASS_BOILERPLATE(Substring) 321 Substring(DataRef &&parent, std::optional<Expr<SubscriptInteger>> &&lower, 322 std::optional<Expr<SubscriptInteger>> &&upper) 323 : parent_{std::move(parent)} { 324 SetBounds(lower, upper); 325 } 326 Substring(StaticDataObject::Pointer &&parent, 327 std::optional<Expr<SubscriptInteger>> &&lower, 328 std::optional<Expr<SubscriptInteger>> &&upper) 329 : parent_{std::move(parent)} { 330 SetBounds(lower, upper); 331 } 332 333 Expr<SubscriptInteger> lower() const; 334 const Expr<SubscriptInteger> *GetLower() const { 335 return lower_.has_value() ? &lower_->value() : nullptr; 336 } 337 Substring &set_lower(Expr<SubscriptInteger> &&); 338 std::optional<Expr<SubscriptInteger>> upper() const; 339 const Expr<SubscriptInteger> *GetUpper() const { 340 return upper_.has_value() ? &upper_->value() : nullptr; 341 } 342 Substring &set_upper(Expr<SubscriptInteger> &&); 343 const Parent &parent() const { return parent_; } 344 Parent &parent() { return parent_; } 345 346 int Rank() const; 347 int Corank() const; 348 template <typename A> const A *GetParentIf() const { 349 return std::get_if<A>(&parent_); 350 } 351 BaseObject GetBaseObject() const; 352 const Symbol *GetLastSymbol() const; 353 std::optional<Expr<SubscriptInteger>> LEN() const; 354 bool operator==(const Substring &) const; 355 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 356 357 std::optional<Expr<SomeCharacter>> Fold(FoldingContext &); 358 359 private: 360 void SetBounds(std::optional<Expr<SubscriptInteger>> &, 361 std::optional<Expr<SubscriptInteger>> &); 362 Parent parent_; 363 std::optional<IndirectSubscriptIntegerExpr> lower_, upper_; 364 }; 365 366 // R915 complex-part-designator 367 // In the F2018 standard, complex parts of array sections are parsed as 368 // variants of sections instead. 369 class ComplexPart { 370 public: 371 ENUM_CLASS(Part, RE, IM) 372 CLASS_BOILERPLATE(ComplexPart) 373 ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {} 374 DataRef &complex() { return complex_; } 375 const DataRef &complex() const { return complex_; } 376 Part part() const { return part_; } 377 int Rank() const; 378 int Corank() const; 379 const Symbol &GetFirstSymbol() const { return complex_.GetFirstSymbol(); } 380 const Symbol &GetLastSymbol() const { return complex_.GetLastSymbol(); } 381 bool operator==(const ComplexPart &) const; 382 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 383 384 private: 385 DataRef complex_; 386 Part part_; 387 }; 388 389 // R901 designator is the most general data reference object, apart from 390 // calls to pointer-valued functions. Its variant holds everything that 391 // a DataRef can, and possibly also a substring reference or a 392 // complex component (%RE/%IM) reference. 393 template <typename T> class Designator { 394 using DataRefs = std::decay_t<decltype(DataRef::u)>; 395 using MaybeSubstring = 396 std::conditional_t<T::category == TypeCategory::Character, 397 std::variant<Substring>, std::variant<>>; 398 using MaybeComplexPart = std::conditional_t<T::category == TypeCategory::Real, 399 std::variant<ComplexPart>, std::variant<>>; 400 using Variant = 401 common::CombineVariants<DataRefs, MaybeSubstring, MaybeComplexPart>; 402 403 public: 404 using Result = T; 405 static_assert( 406 IsSpecificIntrinsicType<Result> || std::is_same_v<Result, SomeDerived>); 407 EVALUATE_UNION_CLASS_BOILERPLATE(Designator) 408 Designator(const DataRef &that) : u{common::CopyVariant<Variant>(that.u)} {} 409 Designator(DataRef &&that) 410 : u{common::MoveVariant<Variant>(std::move(that.u))} {} 411 412 std::optional<DynamicType> GetType() const; 413 int Rank() const; 414 int Corank() const; 415 BaseObject GetBaseObject() const; 416 const Symbol *GetLastSymbol() const; 417 std::optional<Expr<SubscriptInteger>> LEN() const; 418 llvm::raw_ostream &AsFortran(llvm::raw_ostream &o) const; 419 420 Variant u; 421 }; 422 423 FOR_EACH_CHARACTER_KIND(extern template class Designator, ) 424 425 class DescriptorInquiry { 426 public: 427 using Result = SubscriptInteger; 428 ENUM_CLASS(Field, LowerBound, Extent, Stride, Rank, Len) 429 430 CLASS_BOILERPLATE(DescriptorInquiry) 431 DescriptorInquiry(const NamedEntity &, Field, int = 0); 432 DescriptorInquiry(NamedEntity &&, Field, int = 0); 433 434 NamedEntity &base() { return base_; } 435 const NamedEntity &base() const { return base_; } 436 Field field() const { return field_; } 437 int dimension() const { return dimension_; } 438 439 static constexpr int Rank() { return 0; } // always scalar 440 static constexpr int Corank() { return 0; } 441 bool operator==(const DescriptorInquiry &) const; 442 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 443 444 private: 445 NamedEntity base_; 446 Field field_; 447 int dimension_{0}; // zero-based 448 }; 449 450 #define INSTANTIATE_VARIABLE_TEMPLATES \ 451 FOR_EACH_SPECIFIC_TYPE(template class Designator, ) 452 } // namespace Fortran::evaluate 453 #endif // FORTRAN_EVALUATE_VARIABLE_H_ 454