1 //===-- lib/Evaluate/call.cpp ---------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Evaluate/call.h"
10 #include "flang/Common/Fortran.h"
11 #include "flang/Common/idioms.h"
12 #include "flang/Evaluate/characteristics.h"
13 #include "flang/Evaluate/check-expression.h"
14 #include "flang/Evaluate/expression.h"
15 #include "flang/Evaluate/tools.h"
16 #include "flang/Semantics/symbol.h"
18 namespace Fortran::evaluate
{
20 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ActualArgument
)
21 ActualArgument::ActualArgument(Expr
<SomeType
> &&x
) : u_
{std::move(x
)} {}
22 ActualArgument::ActualArgument(common::CopyableIndirection
<Expr
<SomeType
>> &&v
)
24 ActualArgument::ActualArgument(AssumedType x
) : u_
{x
} {}
25 ActualArgument::ActualArgument(common::Label x
) : u_
{x
} {}
26 ActualArgument::~ActualArgument() {}
28 ActualArgument::AssumedType::AssumedType(const Symbol
&symbol
)
30 const semantics::DeclTypeSpec
*type
{symbol
.GetType()};
31 CHECK(type
&& type
->category() == semantics::DeclTypeSpec::TypeStar
);
34 int ActualArgument::AssumedType::Rank() const { return symbol_
->Rank(); }
36 ActualArgument
&ActualArgument::operator=(Expr
<SomeType
> &&expr
) {
41 std::optional
<DynamicType
> ActualArgument::GetType() const {
42 if (const Expr
<SomeType
> *expr
{UnwrapExpr()}) {
43 return expr
->GetType();
44 } else if (std::holds_alternative
<AssumedType
>(u_
)) {
45 return DynamicType::AssumedType();
51 int ActualArgument::Rank() const {
52 if (const Expr
<SomeType
> *expr
{UnwrapExpr()}) {
55 return std::get
<AssumedType
>(u_
).Rank();
59 bool ActualArgument::operator==(const ActualArgument
&that
) const {
60 return keyword_
== that
.keyword_
&& attrs_
== that
.attrs_
&& u_
== that
.u_
;
63 void ActualArgument::Parenthesize() {
64 u_
= evaluate::Parenthesize(std::move(DEREF(UnwrapExpr())));
67 SpecificIntrinsic::SpecificIntrinsic(
68 IntrinsicProcedure n
, characteristics::Procedure
&&chars
)
69 : name
{n
}, characteristics
{
70 new characteristics::Procedure
{std::move(chars
)}} {}
72 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic
)
74 SpecificIntrinsic::~SpecificIntrinsic() {}
76 bool SpecificIntrinsic::operator==(const SpecificIntrinsic
&that
) const {
77 return name
== that
.name
&& characteristics
== that
.characteristics
;
80 ProcedureDesignator::ProcedureDesignator(Component
&&c
)
81 : u
{common::CopyableIndirection
<Component
>::Make(std::move(c
))} {}
83 bool ProcedureDesignator::operator==(const ProcedureDesignator
&that
) const {
87 std::optional
<DynamicType
> ProcedureDesignator::GetType() const {
88 if (const auto *intrinsic
{std::get_if
<SpecificIntrinsic
>(&u
)}) {
89 if (const auto &result
{intrinsic
->characteristics
.value().functionResult
}) {
90 if (const auto *typeAndShape
{result
->GetTypeAndShape()}) {
91 return typeAndShape
->type();
95 return DynamicType::From(GetSymbol());
100 int ProcedureDesignator::Rank() const {
101 if (const Symbol
* symbol
{GetSymbol()}) {
102 // Subtle: will be zero for functions returning procedure pointers
103 return symbol
->Rank();
105 if (const auto *intrinsic
{std::get_if
<SpecificIntrinsic
>(&u
)}) {
106 if (const auto &result
{intrinsic
->characteristics
.value().functionResult
}) {
107 if (const auto *typeAndShape
{result
->GetTypeAndShape()}) {
108 CHECK(!typeAndShape
->attrs().test(
109 characteristics::TypeAndShape::Attr::AssumedRank
));
110 return typeAndShape
->Rank();
112 // Otherwise, intrinsic returns a procedure pointer (e.g. NULL(MOLD=pptr))
118 const Symbol
*ProcedureDesignator::GetInterfaceSymbol() const {
119 if (const Symbol
* symbol
{GetSymbol()}) {
120 const Symbol
&ultimate
{symbol
->GetUltimate()};
121 if (const auto *proc
{ultimate
.detailsIf
<semantics::ProcEntityDetails
>()}) {
122 return proc
->procInterface();
123 } else if (const auto *binding
{
124 ultimate
.detailsIf
<semantics::ProcBindingDetails
>()}) {
125 return &binding
->symbol();
126 } else if (ultimate
.has
<semantics::SubprogramDetails
>()) {
133 bool ProcedureDesignator::IsElemental() const {
134 if (const Symbol
* interface
{GetInterfaceSymbol()}) {
135 return IsElementalProcedure(*interface
);
136 } else if (const Symbol
* symbol
{GetSymbol()}) {
137 return IsElementalProcedure(*symbol
);
138 } else if (const auto *intrinsic
{std::get_if
<SpecificIntrinsic
>(&u
)}) {
139 return intrinsic
->characteristics
.value().attrs
.test(
140 characteristics::Procedure::Attr::Elemental
);
142 DIE("ProcedureDesignator::IsElemental(): no case");
147 bool ProcedureDesignator::IsPure() const {
148 if (const Symbol
* interface
{GetInterfaceSymbol()}) {
149 return IsPureProcedure(*interface
);
150 } else if (const Symbol
* symbol
{GetSymbol()}) {
151 return IsPureProcedure(*symbol
);
152 } else if (const auto *intrinsic
{std::get_if
<SpecificIntrinsic
>(&u
)}) {
153 return intrinsic
->characteristics
.value().attrs
.test(
154 characteristics::Procedure::Attr::Pure
);
156 DIE("ProcedureDesignator::IsPure(): no case");
161 const SpecificIntrinsic
*ProcedureDesignator::GetSpecificIntrinsic() const {
162 return std::get_if
<SpecificIntrinsic
>(&u
);
165 const Component
*ProcedureDesignator::GetComponent() const {
166 if (auto *c
{std::get_if
<common::CopyableIndirection
<Component
>>(&u
)}) {
173 const Symbol
*ProcedureDesignator::GetSymbol() const {
174 return common::visit(
176 [](SymbolRef symbol
) { return &*symbol
; },
177 [](const common::CopyableIndirection
<Component
> &c
) {
178 return &c
.value().GetLastSymbol();
180 [](const auto &) -> const Symbol
* { return nullptr; },
185 const SymbolRef
*ProcedureDesignator::UnwrapSymbolRef() const {
186 return std::get_if
<SymbolRef
>(&u
);
189 std::string
ProcedureDesignator::GetName() const {
190 return common::visit(
192 [](const SpecificIntrinsic
&i
) { return i
.name
; },
193 [](const Symbol
&symbol
) { return symbol
.name().ToString(); },
194 [](const common::CopyableIndirection
<Component
> &c
) {
195 return c
.value().GetLastSymbol().name().ToString();
201 std::optional
<Expr
<SubscriptInteger
>> ProcedureRef::LEN() const {
202 if (const auto *intrinsic
{std::get_if
<SpecificIntrinsic
>(&proc_
.u
)}) {
203 if (intrinsic
->name
== "repeat") {
204 // LEN(REPEAT(ch,n)) == LEN(ch) * n
205 CHECK(arguments_
.size() == 2);
206 const auto *stringArg
{
207 UnwrapExpr
<Expr
<SomeCharacter
>>(arguments_
[0].value())};
208 const auto *nCopiesArg
{
209 UnwrapExpr
<Expr
<SomeInteger
>>(arguments_
[1].value())};
210 CHECK(stringArg
&& nCopiesArg
);
211 if (auto stringLen
{stringArg
->LEN()}) {
212 auto converted
{ConvertTo(*stringLen
, common::Clone(*nCopiesArg
))};
213 return *std::move(stringLen
) * std::move(converted
);
216 // Some other cases (e.g., LEN(CHAR(...))) are handled in
217 // ProcedureDesignator::LEN() because they're independent of the
218 // lengths of the actual arguments.
220 if (auto len
{proc_
.LEN()}) {
221 if (IsActuallyConstant(*len
)) {
224 // TODO: Handle cases where the length of a function result is a
225 // safe expression in terms of actual argument values, after substituting
226 // actual argument expressions for INTENT(IN)/VALUE dummy arguments.
231 int ProcedureRef::Rank() const {
233 for (const auto &arg
: arguments_
) {
235 if (int rank
{arg
->Rank()}; rank
> 0) {
246 ProcedureRef::~ProcedureRef() {}
248 void ProcedureRef::Deleter(ProcedureRef
*p
) { delete p
; }
250 } // namespace Fortran::evaluate