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/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" 17 18 namespace Fortran::evaluate { 19 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) 23 : u_{std::move(v)} {} 24 ActualArgument::ActualArgument(AssumedType x) : u_{x} {} 25 ActualArgument::ActualArgument(common::Label x) : u_{x} {} 26 ActualArgument::~ActualArgument() {} 27 28 ActualArgument::AssumedType::AssumedType(const Symbol &symbol) 29 : symbol_{symbol} { 30 const semantics::DeclTypeSpec *type{symbol.GetType()}; 31 CHECK(type && type->category() == semantics::DeclTypeSpec::TypeStar); 32 } 33 34 int ActualArgument::AssumedType::Rank() const { return symbol_->Rank(); } 35 36 ActualArgument &ActualArgument::operator=(Expr<SomeType> &&expr) { 37 u_ = std::move(expr); 38 return *this; 39 } 40 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(); 46 } else { 47 return std::nullopt; 48 } 49 } 50 51 int ActualArgument::Rank() const { 52 if (const Expr<SomeType> *expr{UnwrapExpr()}) { 53 return expr->Rank(); 54 } else { 55 return std::get<AssumedType>(u_).Rank(); 56 } 57 } 58 59 bool ActualArgument::operator==(const ActualArgument &that) const { 60 return keyword_ == that.keyword_ && isPassedObject_ == that.isPassedObject_ && 61 u_ == that.u_; 62 } 63 64 void ActualArgument::Parenthesize() { 65 u_ = evaluate::Parenthesize(std::move(DEREF(UnwrapExpr()))); 66 } 67 68 SpecificIntrinsic::SpecificIntrinsic( 69 IntrinsicProcedure n, characteristics::Procedure &&chars) 70 : name{n}, characteristics{ 71 new characteristics::Procedure{std::move(chars)}} {} 72 73 DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(SpecificIntrinsic) 74 75 SpecificIntrinsic::~SpecificIntrinsic() {} 76 77 bool SpecificIntrinsic::operator==(const SpecificIntrinsic &that) const { 78 return name == that.name && characteristics == that.characteristics; 79 } 80 81 ProcedureDesignator::ProcedureDesignator(Component &&c) 82 : u{common::CopyableIndirection<Component>::Make(std::move(c))} {} 83 84 bool ProcedureDesignator::operator==(const ProcedureDesignator &that) const { 85 return u == that.u; 86 } 87 88 std::optional<DynamicType> ProcedureDesignator::GetType() const { 89 if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) { 90 if (const auto &result{intrinsic->characteristics.value().functionResult}) { 91 if (const auto *typeAndShape{result->GetTypeAndShape()}) { 92 return typeAndShape->type(); 93 } 94 } 95 } else { 96 return DynamicType::From(GetSymbol()); 97 } 98 return std::nullopt; 99 } 100 101 int ProcedureDesignator::Rank() const { 102 if (const Symbol * symbol{GetSymbol()}) { 103 // Subtle: will be zero for functions returning procedure pointers 104 return symbol->Rank(); 105 } 106 if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) { 107 if (const auto &result{intrinsic->characteristics.value().functionResult}) { 108 if (const auto *typeAndShape{result->GetTypeAndShape()}) { 109 CHECK(!typeAndShape->attrs().test( 110 characteristics::TypeAndShape::Attr::AssumedRank)); 111 return typeAndShape->Rank(); 112 } 113 // Otherwise, intrinsic returns a procedure pointer (e.g. NULL(MOLD=pptr)) 114 } 115 } 116 return 0; 117 } 118 119 const Symbol *ProcedureDesignator::GetInterfaceSymbol() const { 120 if (const Symbol * symbol{GetSymbol()}) { 121 const Symbol &ultimate{symbol->GetUltimate()}; 122 if (const auto *proc{ultimate.detailsIf<semantics::ProcEntityDetails>()}) { 123 return proc->interface().symbol(); 124 } else if (const auto *binding{ 125 ultimate.detailsIf<semantics::ProcBindingDetails>()}) { 126 return &binding->symbol(); 127 } else if (ultimate.has<semantics::SubprogramDetails>()) { 128 return &ultimate; 129 } 130 } 131 return nullptr; 132 } 133 134 bool ProcedureDesignator::IsElemental() const { 135 if (const Symbol * interface{GetInterfaceSymbol()}) { 136 return IsElementalProcedure(*interface); 137 } else if (const Symbol * symbol{GetSymbol()}) { 138 return IsElementalProcedure(*symbol); 139 } else if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) { 140 return intrinsic->characteristics.value().attrs.test( 141 characteristics::Procedure::Attr::Elemental); 142 } else { 143 DIE("ProcedureDesignator::IsElemental(): no case"); 144 } 145 return false; 146 } 147 148 bool ProcedureDesignator::IsPure() const { 149 if (const Symbol * interface{GetInterfaceSymbol()}) { 150 return IsPureProcedure(*interface); 151 } else if (const Symbol * symbol{GetSymbol()}) { 152 return IsPureProcedure(*symbol); 153 } else if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&u)}) { 154 return intrinsic->characteristics.value().attrs.test( 155 characteristics::Procedure::Attr::Pure); 156 } else { 157 DIE("ProcedureDesignator::IsPure(): no case"); 158 } 159 return false; 160 } 161 162 const SpecificIntrinsic *ProcedureDesignator::GetSpecificIntrinsic() const { 163 return std::get_if<SpecificIntrinsic>(&u); 164 } 165 166 const Component *ProcedureDesignator::GetComponent() const { 167 if (auto *c{std::get_if<common::CopyableIndirection<Component>>(&u)}) { 168 return &c->value(); 169 } else { 170 return nullptr; 171 } 172 } 173 174 const Symbol *ProcedureDesignator::GetSymbol() const { 175 return common::visit( 176 common::visitors{ 177 [](SymbolRef symbol) { return &*symbol; }, 178 [](const common::CopyableIndirection<Component> &c) { 179 return &c.value().GetLastSymbol(); 180 }, 181 [](const auto &) -> const Symbol * { return nullptr; }, 182 }, 183 u); 184 } 185 186 std::string ProcedureDesignator::GetName() const { 187 return common::visit( 188 common::visitors{ 189 [](const SpecificIntrinsic &i) { return i.name; }, 190 [](const Symbol &symbol) { return symbol.name().ToString(); }, 191 [](const common::CopyableIndirection<Component> &c) { 192 return c.value().GetLastSymbol().name().ToString(); 193 }, 194 }, 195 u); 196 } 197 198 std::optional<Expr<SubscriptInteger>> ProcedureRef::LEN() const { 199 if (const auto *intrinsic{std::get_if<SpecificIntrinsic>(&proc_.u)}) { 200 if (intrinsic->name == "repeat") { 201 // LEN(REPEAT(ch,n)) == LEN(ch) * n 202 CHECK(arguments_.size() == 2); 203 const auto *stringArg{ 204 UnwrapExpr<Expr<SomeCharacter>>(arguments_[0].value())}; 205 const auto *nCopiesArg{ 206 UnwrapExpr<Expr<SomeInteger>>(arguments_[1].value())}; 207 CHECK(stringArg && nCopiesArg); 208 if (auto stringLen{stringArg->LEN()}) { 209 auto converted{ConvertTo(*stringLen, common::Clone(*nCopiesArg))}; 210 return *std::move(stringLen) * std::move(converted); 211 } 212 } 213 // Some other cases (e.g., LEN(CHAR(...))) are handled in 214 // ProcedureDesignator::LEN() because they're independent of the 215 // lengths of the actual arguments. 216 } 217 if (auto len{proc_.LEN()}) { 218 if (IsActuallyConstant(*len)) { 219 return len; 220 } 221 // TODO: Handle cases where the length of a function result is a 222 // safe expression in terms of actual argument values, after substituting 223 // actual argument expressions for INTENT(IN)/VALUE dummy arguments. 224 } 225 return std::nullopt; 226 } 227 228 int ProcedureRef::Rank() const { 229 if (IsElemental()) { 230 for (const auto &arg : arguments_) { 231 if (arg) { 232 if (int rank{arg->Rank()}; rank > 0) { 233 return rank; 234 } 235 } 236 } 237 return 0; 238 } else { 239 return proc_.Rank(); 240 } 241 } 242 243 ProcedureRef::~ProcedureRef() {} 244 245 void ProcedureRef::Deleter(ProcedureRef *p) { delete p; } 246 247 } // namespace Fortran::evaluate 248