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 18 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ActualArgument) 19 ActualArgument::ActualArgument(Expr<SomeType> &&x) : u_{std::move(x)} {} 20 ActualArgument::ActualArgument(common::CopyableIndirection<Expr<SomeType>> &&v) 21 : u_{std::move(v)} {} 22 ActualArgument::ActualArgument(AssumedType x) : u_{x} {} 23 ActualArgument::~ActualArgument() {} 24 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 31 int ActualArgument::AssumedType::Rank() const { return symbol_->Rank(); } 32 33 ActualArgument &ActualArgument::operator=(Expr<SomeType> &&expr) { 34 u_ = std::move(expr); 35 return *this; 36 } 37 38 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 48 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 56 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 62 void ActualArgument::Parenthesize() { 63 u_ = evaluate::Parenthesize(std::move(DEREF(UnwrapExpr()))); 64 } 65 66 SpecificIntrinsic::SpecificIntrinsic( 67 IntrinsicProcedure n, characteristics::Procedure &&chars) 68 : name{n}, characteristics{ 69 new characteristics::Procedure{std::move(chars)}} {} 70 71 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic) 72 73 SpecificIntrinsic::~SpecificIntrinsic() {} 74 75 bool SpecificIntrinsic::operator==(const SpecificIntrinsic &that) const { 76 return name == that.name && characteristics == that.characteristics; 77 } 78 79 ProcedureDesignator::ProcedureDesignator(Component &&c) 80 : u{common::CopyableIndirection<Component>::Make(std::move(c))} {} 81 82 bool ProcedureDesignator::operator==(const ProcedureDesignator &that) const { 83 return u == that.u; 84 } 85 86 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 99 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 117 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 127 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 141 const SpecificIntrinsic *ProcedureDesignator::GetSpecificIntrinsic() const { 142 return std::get_if<SpecificIntrinsic>(&u); 143 } 144 145 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 153 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 164 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 176 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 198 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 213 ProcedureRef::~ProcedureRef() {} 214 215 void ProcedureRef::Deleter(ProcedureRef *p) { delete p; } 216 217 FOR_EACH_SPECIFIC_TYPE(template class FunctionRef, ) 218 } // namespace Fortran::evaluate 219