1 //===-- lib/Evaluate/call.cpp ---------------------------------------------===//
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 #include "flang/Evaluate/call.h"
10 #include "flang/Common/idioms.h"
11 #include "flang/Evaluate/characteristics.h"
12 #include "flang/Evaluate/expression.h"
13 #include "flang/Evaluate/tools.h"
14 #include "flang/Semantics/symbol.h"
15
16 namespace Fortran::evaluate {
17
DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ActualArgument)18 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ActualArgument)
19 ActualArgument::ActualArgument(Expr<SomeType> &&x) : u_{std::move(x)} {}
ActualArgument(common::CopyableIndirection<Expr<SomeType>> && v)20 ActualArgument::ActualArgument(common::CopyableIndirection<Expr<SomeType>> &&v)
21 : u_{std::move(v)} {}
ActualArgument(AssumedType x)22 ActualArgument::ActualArgument(AssumedType x) : u_{x} {}
~ActualArgument()23 ActualArgument::~ActualArgument() {}
24
AssumedType(const Symbol & symbol)25 ActualArgument::AssumedType::AssumedType(const Symbol &symbol)
26 : symbol_{symbol} {
27 const semantics::DeclTypeSpec *type{symbol.GetType()};
28 CHECK(type && type->category() == semantics::DeclTypeSpec::TypeStar);
29 }
30
Rank() const31 int ActualArgument::AssumedType::Rank() const { return symbol_->Rank(); }
32
operator =(Expr<SomeType> && expr)33 ActualArgument &ActualArgument::operator=(Expr<SomeType> &&expr) {
34 u_ = std::move(expr);
35 return *this;
36 }
37
GetType() const38 std::optional<DynamicType> ActualArgument::GetType() const {
39 if (const Expr<SomeType> *expr{UnwrapExpr()}) {
40 return expr->GetType();
41 } else if (std::holds_alternative<AssumedType>(u_)) {
42 return DynamicType::AssumedType();
43 } else {
44 return std::nullopt;
45 }
46 }
47
Rank() const48 int ActualArgument::Rank() const {
49 if (const Expr<SomeType> *expr{UnwrapExpr()}) {
50 return expr->Rank();
51 } else {
52 return std::get<AssumedType>(u_).Rank();
53 }
54 }
55
operator ==(const ActualArgument & that) const56 bool ActualArgument::operator==(const ActualArgument &that) const {
57 return keyword_ == that.keyword_ &&
58 isAlternateReturn_ == that.isAlternateReturn_ &&
59 isPassedObject_ == that.isPassedObject_ && u_ == that.u_;
60 }
61
Parenthesize()62 void ActualArgument::Parenthesize() {
63 u_ = evaluate::Parenthesize(std::move(DEREF(UnwrapExpr())));
64 }
65
SpecificIntrinsic(IntrinsicProcedure n,characteristics::Procedure && chars)66 SpecificIntrinsic::SpecificIntrinsic(
67 IntrinsicProcedure n, characteristics::Procedure &&chars)
68 : name{n}, characteristics{
69 new characteristics::Procedure{std::move(chars)}} {}
70
DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic)71 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic)
72
73 SpecificIntrinsic::~SpecificIntrinsic() {}
74
operator ==(const SpecificIntrinsic & that) const75 bool SpecificIntrinsic::operator==(const SpecificIntrinsic &that) const {
76 return name == that.name && characteristics == that.characteristics;
77 }
78
ProcedureDesignator(Component && c)79 ProcedureDesignator::ProcedureDesignator(Component &&c)
80 : u{common::CopyableIndirection<Component>::Make(std::move(c))} {}
81
operator ==(const ProcedureDesignator & that) const82 bool ProcedureDesignator::operator==(const ProcedureDesignator &that) const {
83 return u == that.u;
84 }
85
GetType() const86 std::optional<DynamicType> ProcedureDesignator::GetType() const {
87 if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
88 if (const auto &result{intrinsic->characteristics.value().functionResult}) {
89 if (const auto *typeAndShape{result->GetTypeAndShape()}) {
90 return typeAndShape->type();
91 }
92 }
93 } else {
94 return DynamicType::From(GetSymbol());
95 }
96 return std::nullopt;
97 }
98
Rank() const99 int ProcedureDesignator::Rank() const {
100 if (const Symbol * symbol{GetSymbol()}) {
101 // Subtle: will be zero for functions returning procedure pointers
102 return symbol->Rank();
103 }
104 if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
105 if (const auto &result{intrinsic->characteristics.value().functionResult}) {
106 if (const auto *typeAndShape{result->GetTypeAndShape()}) {
107 CHECK(!typeAndShape->attrs().test(
108 characteristics::TypeAndShape::Attr::AssumedRank));
109 return typeAndShape->Rank();
110 }
111 // Otherwise, intrinsic returns a procedure pointer (e.g. NULL(MOLD=pptr))
112 }
113 }
114 return 0;
115 }
116
GetInterfaceSymbol() const117 const Symbol *ProcedureDesignator::GetInterfaceSymbol() const {
118 if (const Symbol * symbol{GetSymbol()}) {
119 if (const auto *details{
120 symbol->detailsIf<semantics::ProcEntityDetails>()}) {
121 return details->interface().symbol();
122 }
123 }
124 return nullptr;
125 }
126
IsElemental() const127 bool ProcedureDesignator::IsElemental() const {
128 if (const Symbol * interface{GetInterfaceSymbol()}) {
129 return interface->attrs().test(semantics::Attr::ELEMENTAL);
130 } else if (const Symbol * symbol{GetSymbol()}) {
131 return symbol->attrs().test(semantics::Attr::ELEMENTAL);
132 } else if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) {
133 return intrinsic->characteristics.value().attrs.test(
134 characteristics::Procedure::Attr::Elemental);
135 } else {
136 DIE("ProcedureDesignator::IsElemental(): no case");
137 }
138 return false;
139 }
140
GetSpecificIntrinsic() const141 const SpecificIntrinsic *ProcedureDesignator::GetSpecificIntrinsic() const {
142 return std::get_if<SpecificIntrinsic>(&u);
143 }
144
GetComponent() const145 const Component *ProcedureDesignator::GetComponent() const {
146 if (auto *c{std::get_if<common::CopyableIndirection<Component>>(&u)}) {
147 return &c->value();
148 } else {
149 return nullptr;
150 }
151 }
152
GetSymbol() const153 const Symbol *ProcedureDesignator::GetSymbol() const {
154 return std::visit(common::visitors{
155 [](SymbolRef symbol) { return &*symbol; },
156 [](const common::CopyableIndirection<Component> &c) {
157 return &c.value().GetLastSymbol();
158 },
159 [](const auto &) -> const Symbol * { return nullptr; },
160 },
161 u);
162 }
163
GetName() const164 std::string ProcedureDesignator::GetName() const {
165 return std::visit(
166 common::visitors{
167 [](const SpecificIntrinsic &i) { return i.name; },
168 [](const Symbol &symbol) { return symbol.name().ToString(); },
169 [](const common::CopyableIndirection<Component> &c) {
170 return c.value().GetLastSymbol().name().ToString();
171 },
172 },
173 u);
174 }
175
LEN() const176 std::optional<Expr<SubscriptInteger>> ProcedureRef::LEN() const {
177 if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&proc_.u)}) {
178 if (intrinsic->name == "repeat") {
179 // LEN(REPEAT(ch,n)) == LEN(ch) * n
180 CHECK(arguments_.size() == 2);
181 const auto *stringArg{
182 UnwrapExpr<Expr<SomeCharacter>>(arguments_[0].value())};
183 const auto *nCopiesArg{
184 UnwrapExpr<Expr<SomeInteger>>(arguments_[1].value())};
185 CHECK(stringArg && nCopiesArg);
186 if (auto stringLen{stringArg->LEN()}) {
187 auto converted{ConvertTo(*stringLen, common::Clone(*nCopiesArg))};
188 return *std::move(stringLen) * std::move(converted);
189 }
190 }
191 // Some other cases (e.g., LEN(CHAR(...))) are handled in
192 // ProcedureDesignator::LEN() because they're independent of the
193 // lengths of the actual arguments.
194 }
195 return proc_.LEN();
196 }
197
Rank() const198 int ProcedureRef::Rank() const {
199 if (IsElemental()) {
200 for (const auto &arg : arguments_) {
201 if (arg) {
202 if (int rank{arg->Rank()}; rank > 0) {
203 return rank;
204 }
205 }
206 }
207 return 0;
208 } else {
209 return proc_.Rank();
210 }
211 }
212
~ProcedureRef()213 ProcedureRef::~ProcedureRef() {}
214
Deleter(ProcedureRef * p)215 void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
216
217 FOR_EACH_SPECIFIC_TYPE(template class FunctionRef, )
218 } // namespace Fortran::evaluate
219