0e78839b2ccc3c5deedec2ab60f3463703973105
[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   void set_keyword(parser::CharBlock x) { keyword_ = x; }
115   bool isAlternateReturn() const {
116     return std::holds_alternative<common::Label>(u_);
117   }
118   bool isPassedObject() const { return isPassedObject_; }
119   void set_isPassedObject(bool yes = true) { isPassedObject_ = yes; }
120
121   bool Matches(const characteristics::DummyArgument &) const;
122   common::Intent dummyIntent() const { return dummyIntent_; }
123   ActualArgument &set_dummyIntent(common::Intent intent) {
124     dummyIntent_ = intent;
125     return *this;
126   }
127
128   // Wrap this argument in parentheses
129   void Parenthesize();
130
131   // TODO: Mark legacy %VAL and %REF arguments
132
133 private:
134   // Subtlety: There is a distinction that must be maintained here between an
135   // actual argument expression that is a variable and one that is not,
136   // e.g. between X and (X).  The parser attempts to parse each argument
137   // first as a variable, then as an expression, and the distinction appears
138   // in the parse tree.
139   std::variant<common::CopyableIndirection<Expr<SomeType>>, AssumedType,
140       common::Label>
141       u_;
142   std::optional<parser::CharBlock> keyword_;
143   bool isPassedObject_{false};
144   common::Intent dummyIntent_{common::Intent::Default};
145 };
146
147 using ActualArguments = std::vector<std::optional<ActualArgument>>;
148
149 // Intrinsics are identified by their names and the characteristics
150 // of their arguments, at least for now.
151 using IntrinsicProcedure = std::string;
152
153 struct SpecificIntrinsic {
154   SpecificIntrinsic(IntrinsicProcedure, characteristics::Procedure &&);
155   DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic)
156   ~SpecificIntrinsic();
157   bool operator==(const SpecificIntrinsic &) const;
158   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
159
160   IntrinsicProcedure name;
161   bool isRestrictedSpecific{false}; // if true, can only call it, not pass it
162   common::CopyableIndirection<characteristics::Procedure> characteristics;
163 };
164
165 struct ProcedureDesignator {
166   EVALUATE_UNION_CLASS_BOILERPLATE(ProcedureDesignator)
167   explicit ProcedureDesignator(SpecificIntrinsic &&i) : u{std::move(i)} {}
168   explicit ProcedureDesignator(const Symbol &n) : u{n} {}
169   explicit ProcedureDesignator(Component &&);
170
171   // Exactly one of these will return a non-null pointer.
172   const SpecificIntrinsic *GetSpecificIntrinsic() const;
173   const Symbol *GetSymbol() const; // symbol or component symbol
174
175   // For references to NOPASS components and bindings only.
176   // References to PASS components and bindings are represented
177   // with the symbol below and the base object DataRef in the
178   // passed-object ActualArgument.
179   // Always null when the procedure is intrinsic.
180   const Component *GetComponent() const;
181
182   const Symbol *GetInterfaceSymbol() const;
183
184   std::string GetName() const;
185   std::optional<DynamicType> GetType() const;
186   int Rank() const;
187   bool IsElemental() const;
188   std::optional<Expr<SubscriptInteger>> LEN() const;
189   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
190
191   std::variant<SpecificIntrinsic, SymbolRef,
192       common::CopyableIndirection<Component>>
193       u;
194 };
195
196 class ProcedureRef {
197 public:
198   CLASS_BOILERPLATE(ProcedureRef)
199   ProcedureRef(ProcedureDesignator &&p, ActualArguments &&a,
200       bool hasAlternateReturns = false)
201       : proc_{std::move(p)}, arguments_{std::move(a)},
202         hasAlternateReturns_{hasAlternateReturns} {}
203   ~ProcedureRef();
204   static void Deleter(ProcedureRef *);
205
206   ProcedureDesignator &proc() { return proc_; }
207   const ProcedureDesignator &proc() const { return proc_; }
208   ActualArguments &arguments() { return arguments_; }
209   const ActualArguments &arguments() const { return arguments_; }
210
211   std::optional<Expr<SubscriptInteger>> LEN() const;
212   int Rank() const;
213   bool IsElemental() const { return proc_.IsElemental(); }
214   bool hasAlternateReturns() const { return hasAlternateReturns_; }
215   bool operator==(const ProcedureRef &) const;
216   llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
217
218 protected:
219   ProcedureDesignator proc_;
220   ActualArguments arguments_;
221   bool hasAlternateReturns_;
222 };
223
224 template <typename A> class FunctionRef : public ProcedureRef {
225 public:
226   using Result = A;
227   CLASS_BOILERPLATE(FunctionRef)
228   explicit FunctionRef(ProcedureRef &&pr) : ProcedureRef{std::move(pr)} {}
229   FunctionRef(ProcedureDesignator &&p, ActualArguments &&a)
230       : ProcedureRef{std::move(p), std::move(a)} {}
231
232   std::optional<DynamicType> GetType() const { return proc_.GetType(); }
233   std::optional<Constant<Result>> Fold(FoldingContext &); // for intrinsics
234 };
235
236 FOR_EACH_SPECIFIC_TYPE(extern template class FunctionRef, )
237 } // namespace Fortran::evaluate
238 #endif // FORTRAN_EVALUATE_CALL_H_