• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- include/flang/Evaluate/characteristics.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 // Defines data structures to represent "characteristics" of Fortran
10 // procedures and other entities as they are specified in section 15.3
11 // of Fortran 2018.
12 
13 #ifndef FORTRAN_EVALUATE_CHARACTERISTICS_H_
14 #define FORTRAN_EVALUATE_CHARACTERISTICS_H_
15 
16 #include "common.h"
17 #include "expression.h"
18 #include "shape.h"
19 #include "type.h"
20 #include "flang/Common/Fortran.h"
21 #include "flang/Common/enum-set.h"
22 #include "flang/Common/idioms.h"
23 #include "flang/Common/indirection.h"
24 #include "flang/Parser/char-block.h"
25 #include "flang/Semantics/symbol.h"
26 #include <optional>
27 #include <string>
28 #include <variant>
29 #include <vector>
30 
31 namespace llvm {
32 class raw_ostream;
33 }
34 
35 namespace Fortran::evaluate::characteristics {
36 struct Procedure;
37 }
38 extern template class Fortran::common::Indirection<
39     Fortran::evaluate::characteristics::Procedure, true>;
40 
41 namespace Fortran::evaluate::characteristics {
42 
43 using common::CopyableIndirection;
44 
45 // Are these procedures distinguishable for a generic name or FINAL?
46 bool Distinguishable(const Procedure &, const Procedure &);
47 // Are these procedures distinguishable for a generic operator or assignment?
48 bool DistinguishableOpOrAssign(const Procedure &, const Procedure &);
49 
50 // Shapes of function results and dummy arguments have to have
51 // the same rank, the same deferred dimensions, and the same
52 // values for explicit dimensions when constant.
53 bool ShapesAreCompatible(const Shape &, const Shape &);
54 
55 class TypeAndShape {
56 public:
57   ENUM_CLASS(
58       Attr, AssumedRank, AssumedShape, AssumedSize, DeferredShape, Coarray)
59   using Attrs = common::EnumSet<Attr, Attr_enumSize>;
60 
TypeAndShape(DynamicType t)61   explicit TypeAndShape(DynamicType t) : type_{t} { AcquireLEN(); }
TypeAndShape(DynamicType t,int rank)62   TypeAndShape(DynamicType t, int rank) : type_{t}, shape_(rank) {
63     AcquireLEN();
64   }
TypeAndShape(DynamicType t,Shape && s)65   TypeAndShape(DynamicType t, Shape &&s) : type_{t}, shape_{std::move(s)} {
66     AcquireLEN();
67   }
TypeAndShape(DynamicType t,std::optional<Shape> && s)68   TypeAndShape(DynamicType t, std::optional<Shape> &&s) : type_{t} {
69     if (s) {
70       shape_ = std::move(*s);
71     }
72     AcquireLEN();
73   }
74   DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(TypeAndShape)
75 
76   bool operator==(const TypeAndShape &) const;
77   bool operator!=(const TypeAndShape &that) const { return !(*this == that); }
78 
79   static std::optional<TypeAndShape> Characterize(
80       const semantics::Symbol &, FoldingContext &);
81   static std::optional<TypeAndShape> Characterize(
82       const semantics::ObjectEntityDetails &, FoldingContext &);
83   static std::optional<TypeAndShape> Characterize(
84       const semantics::ProcInterface &);
85   static std::optional<TypeAndShape> Characterize(
86       const semantics::DeclTypeSpec &);
87   static std::optional<TypeAndShape> Characterize(
88       const ActualArgument &, FoldingContext &);
89 
90   template <typename A>
Characterize(const A & x,FoldingContext & context)91   static std::optional<TypeAndShape> Characterize(
92       const A &x, FoldingContext &context) {
93     if (const auto *symbol{UnwrapWholeSymbolDataRef(x)}) {
94       if (auto result{Characterize(*symbol, context)}) {
95         return result;
96       }
97     }
98     if (auto type{x.GetType()}) {
99       if (auto shape{GetShape(context, x)}) {
100         TypeAndShape result{*type, std::move(*shape)};
101         if (type->category() == TypeCategory::Character) {
102           if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(x)}) {
103             if (auto length{chExpr->LEN()}) {
104               result.set_LEN(Fold(context, std::move(*length)));
105             }
106           }
107         }
108         return result;
109       }
110     }
111     return std::nullopt;
112   }
113   template <typename A>
Characterize(const std::optional<A> & x,FoldingContext & context)114   static std::optional<TypeAndShape> Characterize(
115       const std::optional<A> &x, FoldingContext &context) {
116     if (x) {
117       return Characterize(*x, context);
118     } else {
119       return std::nullopt;
120     }
121   }
122   template <typename A>
Characterize(const A * x,FoldingContext & context)123   static std::optional<TypeAndShape> Characterize(
124       const A *x, FoldingContext &context) {
125     if (x) {
126       return Characterize(*x, context);
127     } else {
128       return std::nullopt;
129     }
130   }
131 
type()132   DynamicType type() const { return type_; }
set_type(DynamicType t)133   TypeAndShape &set_type(DynamicType t) {
134     type_ = t;
135     return *this;
136   }
LEN()137   const std::optional<Expr<SubscriptInteger>> &LEN() const { return LEN_; }
set_LEN(Expr<SubscriptInteger> && len)138   TypeAndShape &set_LEN(Expr<SubscriptInteger> &&len) {
139     LEN_ = std::move(len);
140     return *this;
141   }
shape()142   const Shape &shape() const { return shape_; }
attrs()143   const Attrs &attrs() const { return attrs_; }
corank()144   int corank() const { return corank_; }
145 
Rank()146   int Rank() const { return GetRank(shape_); }
147   bool IsCompatibleWith(parser::ContextualMessages &, const TypeAndShape &that,
148       const char *thisIs = "POINTER", const char *thatIs = "TARGET",
149       bool isElemental = false) const;
150   std::optional<Expr<SubscriptInteger>> MeasureSizeInBytes(
151       FoldingContext * = nullptr) const;
152 
153   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
154 
155 private:
156   static std::optional<TypeAndShape> Characterize(
157       const semantics::AssocEntityDetails &, FoldingContext &);
158   static std::optional<TypeAndShape> Characterize(
159       const semantics::ProcEntityDetails &);
160   void AcquireShape(const semantics::ObjectEntityDetails &, FoldingContext &);
161   void AcquireLEN();
162 
163 protected:
164   DynamicType type_;
165   std::optional<Expr<SubscriptInteger>> LEN_;
166   Shape shape_;
167   Attrs attrs_;
168   int corank_{0};
169 };
170 
171 // 15.3.2.2
172 struct DummyDataObject {
173   ENUM_CLASS(Attr, Optional, Allocatable, Asynchronous, Contiguous, Value,
174       Volatile, Pointer, Target)
175   using Attrs = common::EnumSet<Attr, Attr_enumSize>;
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTSDummyDataObject176   DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(DummyDataObject)
177   explicit DummyDataObject(const TypeAndShape &t) : type{t} {}
DummyDataObjectDummyDataObject178   explicit DummyDataObject(TypeAndShape &&t) : type{std::move(t)} {}
DummyDataObjectDummyDataObject179   explicit DummyDataObject(DynamicType t) : type{t} {}
180   bool operator==(const DummyDataObject &) const;
181   bool operator!=(const DummyDataObject &that) const {
182     return !(*this == that);
183   }
184   static std::optional<DummyDataObject> Characterize(
185       const semantics::Symbol &, FoldingContext &);
186   bool CanBePassedViaImplicitInterface() const;
187   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
188   TypeAndShape type;
189   std::vector<Expr<SubscriptInteger>> coshape;
190   common::Intent intent{common::Intent::Default};
191   Attrs attrs;
192 };
193 
194 // 15.3.2.3
195 struct DummyProcedure {
196   ENUM_CLASS(Attr, Pointer, Optional)
197   using Attrs = common::EnumSet<Attr, Attr_enumSize>;
198   DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(DummyProcedure)
199   explicit DummyProcedure(Procedure &&);
200   bool operator==(const DummyProcedure &) const;
201   bool operator!=(const DummyProcedure &that) const { return !(*this == that); }
202   static std::optional<DummyProcedure> Characterize(
203       const semantics::Symbol &, FoldingContext &context);
204   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
205   CopyableIndirection<Procedure> procedure;
206   common::Intent intent{common::Intent::Default};
207   Attrs attrs;
208 };
209 
210 // 15.3.2.4
211 struct AlternateReturn {
212   bool operator==(const AlternateReturn &) const { return true; }
213   bool operator!=(const AlternateReturn &) const { return false; }
214   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
215 };
216 
217 // 15.3.2.1
218 struct DummyArgument {
219   DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(DummyArgument)
DummyArgumentDummyArgument220   DummyArgument(std::string &&name, DummyDataObject &&x)
221       : name{std::move(name)}, u{std::move(x)} {}
DummyArgumentDummyArgument222   DummyArgument(std::string &&name, DummyProcedure &&x)
223       : name{std::move(name)}, u{std::move(x)} {}
DummyArgumentDummyArgument224   explicit DummyArgument(AlternateReturn &&x) : u{std::move(x)} {}
225   ~DummyArgument();
226   bool operator==(const DummyArgument &) const;
227   bool operator!=(const DummyArgument &that) const { return !(*this == that); }
228   static std::optional<DummyArgument> Characterize(
229       const semantics::Symbol &, FoldingContext &);
230   static std::optional<DummyArgument> FromActual(
231       std::string &&, const Expr<SomeType> &, FoldingContext &);
232   bool IsOptional() const;
233   void SetOptional(bool = true);
234   common::Intent GetIntent() const;
235   void SetIntent(common::Intent);
236   bool CanBePassedViaImplicitInterface() const;
237   bool IsTypelessIntrinsicDummy() const;
238   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
239   // name and pass are not characteristics and so does not participate in
240   // operator== but are needed to determine if procedures are distinguishable
241   std::string name;
242   bool pass{false}; // is this the PASS argument of its procedure
243   std::variant<DummyDataObject, DummyProcedure, AlternateReturn> u;
244 };
245 
246 using DummyArguments = std::vector<DummyArgument>;
247 
248 // 15.3.3
249 struct FunctionResult {
250   ENUM_CLASS(Attr, Allocatable, Pointer, Contiguous)
251   using Attrs = common::EnumSet<Attr, Attr_enumSize>;
252   DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(FunctionResult)
253   explicit FunctionResult(DynamicType);
254   explicit FunctionResult(TypeAndShape &&);
255   explicit FunctionResult(Procedure &&);
256   ~FunctionResult();
257   bool operator==(const FunctionResult &) const;
258   bool operator!=(const FunctionResult &that) const { return !(*this == that); }
259   static std::optional<FunctionResult> Characterize(
260       const Symbol &, FoldingContext &);
261 
262   bool IsAssumedLengthCharacter() const;
263 
IsProcedurePointerFunctionResult264   const Procedure *IsProcedurePointer() const {
265     if (const auto *pp{std::get_if<CopyableIndirection<Procedure>>(&u)}) {
266       return &pp->value();
267     } else {
268       return nullptr;
269     }
270   }
GetTypeAndShapeFunctionResult271   const TypeAndShape *GetTypeAndShape() const {
272     return std::get_if<TypeAndShape>(&u);
273   }
SetTypeFunctionResult274   void SetType(DynamicType t) { std::get<TypeAndShape>(u).set_type(t); }
275   bool CanBeReturnedViaImplicitInterface() const;
276 
277   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
278 
279   Attrs attrs;
280   std::variant<TypeAndShape, CopyableIndirection<Procedure>> u;
281 };
282 
283 // 15.3.1
284 struct Procedure {
285   ENUM_CLASS(
286       Attr, Pure, Elemental, BindC, ImplicitInterface, NullPointer, Subroutine)
287   using Attrs = common::EnumSet<Attr, Attr_enumSize>;
288   Procedure(FunctionResult &&, DummyArguments &&, Attrs);
289   Procedure(DummyArguments &&, Attrs); // for subroutines and NULL()
290   DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(Procedure)
291   ~Procedure();
292   bool operator==(const Procedure &) const;
293   bool operator!=(const Procedure &that) const { return !(*this == that); }
294 
295   // Characterizes the procedure represented by a symbol, which may be an
296   // "unrestricted specific intrinsic function".
297   static std::optional<Procedure> Characterize(
298       const semantics::Symbol &, FoldingContext &);
299   static std::optional<Procedure> Characterize(
300       const ProcedureDesignator &, FoldingContext &);
301   static std::optional<Procedure> Characterize(
302       const ProcedureRef &, FoldingContext &);
303 
304   // At most one of these will return true.
305   // For "EXTERNAL P" with no type for or calls to P, both will be false.
IsFunctionProcedure306   bool IsFunction() const { return functionResult.has_value(); }
IsSubroutineProcedure307   bool IsSubroutine() const { return attrs.test(Attr::Subroutine); }
308 
IsPureProcedure309   bool IsPure() const { return attrs.test(Attr::Pure); }
IsElementalProcedure310   bool IsElemental() const { return attrs.test(Attr::Elemental); }
IsBindCProcedure311   bool IsBindC() const { return attrs.test(Attr::BindC); }
HasExplicitInterfaceProcedure312   bool HasExplicitInterface() const {
313     return !attrs.test(Attr::ImplicitInterface);
314   }
315   int FindPassIndex(std::optional<parser::CharBlock>) const;
316   bool CanBeCalledViaImplicitInterface() const;
317   bool CanOverride(const Procedure &, std::optional<int> passIndex) const;
318   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
319 
320   std::optional<FunctionResult> functionResult;
321   DummyArguments dummyArguments;
322   Attrs attrs;
323 
324 private:
ProcedureProcedure325   Procedure() {}
326 };
327 
328 } // namespace Fortran::evaluate::characteristics
329 #endif // FORTRAN_EVALUATE_CHARACTERISTICS_H_
330