[flang] Infrastructure improvements in utility routines
[lldb.git] / flang / include / flang / Evaluate / call.h
1 //===-- include/flang/Evaluate/call.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_CALL_H_
10 #define FORTRAN_EVALUATE_CALL_H_
11
12 #include "common.h"
13 #include "constant.h"
14 #include "formatting.h"
15 #include "type.h"
16 #include "flang/Common/Fortran.h"
17 #include "flang/Common/indirection.h"
18 #include "flang/Common/reference.h"
19 #include "flang/Parser/char-block.h"
20 #include "flang/Semantics/attr.h"
21 #include <optional>
22 #include <vector>
23
24 namespace llvm {
25 class raw_ostream;
26 }
27
28 namespace Fortran::semantics {
29 class Symbol;
30 }
31
32 // Mutually referential data structures are represented here with forward
33 // declarations of hitherto undefined class types and a level of indirection.
34 namespace Fortran::evaluate {
35 class Component;
36 class IntrinsicProcTable;
37 } // namespace Fortran::evaluate
38 namespace Fortran::evaluate::characteristics {
39 struct DummyArgument;
40 struct Procedure;
41 } // namespace Fortran::evaluate::characteristics
42
43 extern template class Fortran::common::Indirection<Fortran::evaluate::Component,
44     true>;
45 extern template class Fortran::common::Indirection<
46     Fortran::evaluate::characteristics::Procedure, true>;
47
48 namespace Fortran::evaluate {
49
50 using semantics::Symbol;
51 using SymbolRef = common::Reference<const Symbol>;
52
53 class ActualArgument {
54 public:
55   // Dummy arguments that are TYPE(*) can be forwarded as actual arguments.
56   // Since that's the only thing one may do with them in Fortran, they're
57   // represented in expressions as a special case of an actual argument.
58   class AssumedType {
59   public:
60     explicit AssumedType(const Symbol &);
61     DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(AssumedType)
62     const Symbol &symbol() const { return symbol_; }
63     int Rank() const;
64     bool operator==(const AssumedType &that) const {
65       return &*symbol_ == &*that.symbol_;
66     }
67     llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
68
69   private:
70     SymbolRef symbol_;
71   };
72
73   DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(ActualArgument)
74   explicit ActualArgument(Expr<SomeType> &&);
75   explicit ActualArgument(common::CopyableIndirection<Expr<SomeType>> &&);
76   explicit ActualArgument(AssumedType);
77   explicit ActualArgument(common::Label);
78   ~ActualArgument();
79   ActualArgument &operator=(Expr<SomeType> &&);
80
81   Expr<SomeType> *UnwrapExpr() {
82     if (auto *p{
83             std::get_if<common::CopyableIndirection<Expr<SomeType>>>(&u_)}) {
84       return &p->value();
85     } else {
86       return nullptr;
87     }
88   }
89   const Expr<SomeType> *UnwrapExpr() const {
90     if (const auto *p{
91             std::get_if<common::CopyableIndirection<Expr<SomeType>>>(&u_)}) {
92       return &p->value();
93     } else {
94       return nullptr;
95     }
96   }
97
98   const Symbol *GetAssumedTypeDummy() const {
99     if (const AssumedType * aType{std::get_if<AssumedType>(&u_)}) {
100       return &aType->symbol();
101     } else {
102       return nullptr;
103     }
104   }
105
106   common::Label GetLabel() const { return std::get<common::Label>(u_); }
107
108   std::optional<DynamicType> GetType() const;
109   int Rank() const;
110   bool operator==(const ActualArgument &) const;
111   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
112
113   std::optional<parser::CharBlock> keyword() const { return keyword_; }
114   ActualArgument &set_keyword(parser::CharBlock x) {
115     keyword_ = x;
116     return *this;
117   }
118   bool isAlternateReturn() const {
119     return std::holds_alternative<common::Label>(u_);
120   }
121   bool isPassedObject() const { return isPassedObject_; }
122   ActualArgument &set_isPassedObject(bool yes = true) {
123     isPassedObject_ = yes;
124     return *this;
125   }
126
127   bool Matches(const characteristics::DummyArgument &) const;
128   common::Intent dummyIntent() const { return dummyIntent_; }
129   ActualArgument &set_dummyIntent(common::Intent intent) {
130     dummyIntent_ = intent;
131     return *this;
132   }
133
134   // Wrap this argument in parentheses
135   void Parenthesize();
136
137   // TODO: Mark legacy %VAL and %REF arguments
138
139 private:
140   // Subtlety: There is a distinction that must be maintained here between an
141   // actual argument expression that is a variable and one that is not,
142   // e.g. between X and (X).  The parser attempts to parse each argument
143   // first as a variable, then as an expression, and the distinction appears
144   // in the parse tree.
145   std::variant<common::CopyableIndirection<Expr<SomeType>>, AssumedType,
146       common::Label>
147       u_;
148   std::optional<parser::CharBlock> keyword_;
149   bool isPassedObject_{false};
150   common::Intent dummyIntent_{common::Intent::Default};
151 };
152
153 using ActualArguments = std::vector<std::optional<ActualArgument>>;
154
155 // Intrinsics are identified by their names and the characteristics
156 // of their arguments, at least for now.
157 using IntrinsicProcedure = std::string;
158
159 struct SpecificIntrinsic {
160   SpecificIntrinsic(IntrinsicProcedure, characteristics::Procedure &&);
161   DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic)
162   ~SpecificIntrinsic();
163   bool operator==(const SpecificIntrinsic &) const;
164   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
165
166   IntrinsicProcedure name;
167   bool isRestrictedSpecific{false}; // if true, can only call it, not pass it
168   common::CopyableIndirection<characteristics::Procedure> characteristics;
169 };
170
171 struct ProcedureDesignator {
172   EVALUATE_UNION_CLASS_BOILERPLATE(ProcedureDesignator)
173   explicit ProcedureDesignator(SpecificIntrinsic &&i) : u{std::move(i)} {}
174   explicit ProcedureDesignator(const Symbol &n) : u{n} {}
175   explicit ProcedureDesignator(Component &&);
176
177   // Exactly one of these will return a non-null pointer.
178   const SpecificIntrinsic *GetSpecificIntrinsic() const;
179   const Symbol *GetSymbol() const; // symbol or component symbol
180
181   // For references to NOPASS components and bindings only.
182   // References to PASS components and bindings are represented
183   // with the symbol below and the base object DataRef in the
184   // passed-object ActualArgument.
185   // Always null when the procedure is intrinsic.
186   const Component *GetComponent() const;
187
188   const Symbol *GetInterfaceSymbol() const;
189
190   std::string GetName() const;
191   std::optional<DynamicType> GetType() const;
192   int Rank() const;
193   bool IsElemental() const;
194   std::optional<Expr<SubscriptInteger>> LEN() const;
195   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
196
197   std::variant<SpecificIntrinsic, SymbolRef,
198       common::CopyableIndirection<Component>>
199       u;
200 };
201
202 class ProcedureRef {
203 public:
204   CLASS_BOILERPLATE(ProcedureRef)
205   ProcedureRef(ProcedureDesignator &&p, ActualArguments &&a,
206       bool hasAlternateReturns = false)
207       : proc_{std::move(p)}, arguments_{std::move(a)},
208         hasAlternateReturns_{hasAlternateReturns} {}
209   ~ProcedureRef();
210   static void Deleter(ProcedureRef *);
211
212   ProcedureDesignator &proc() { return proc_; }
213   const ProcedureDesignator &proc() const { return proc_; }
214   ActualArguments &arguments() { return arguments_; }
215   const ActualArguments &arguments() const { return arguments_; }
216
217   std::optional<Expr<SubscriptInteger>> LEN() const;
218   int Rank() const;
219   bool IsElemental() const { return proc_.IsElemental(); }
220   bool hasAlternateReturns() const { return hasAlternateReturns_; }
221   bool operator==(const ProcedureRef &) const;
222   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
223
224 protected:
225   ProcedureDesignator proc_;
226   ActualArguments arguments_;
227   bool hasAlternateReturns_;
228 };
229
230 template <typename A> class FunctionRef : public ProcedureRef {
231 public:
232   using Result = A;
233   CLASS_BOILERPLATE(FunctionRef)
234   explicit FunctionRef(ProcedureRef &&pr) : ProcedureRef{std::move(pr)} {}
235   FunctionRef(ProcedureDesignator &&p, ActualArguments &&a)
236       : ProcedureRef{std::move(p), std::move(a)} {}
237
238   std::optional<DynamicType> GetType() const { return proc_.GetType(); }
239   std::optional<Constant<Result>> Fold(FoldingContext &); // for intrinsics
240 };
241
242 FOR_EACH_SPECIFIC_TYPE(extern template class FunctionRef, )
243 } // namespace Fortran::evaluate
244 #endif // FORTRAN_EVALUATE_CALL_H_