1 //===-- lib/Evaluate/tools.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/tools.h" 10 #include "flang/Common/idioms.h" 11 #include "flang/Evaluate/characteristics.h" 12 #include "flang/Evaluate/traverse.h" 13 #include "flang/Parser/message.h" 14 #include "flang/Semantics/tools.h" 15 #include <algorithm> 16 #include <variant> 17 18 using namespace Fortran::parser::literals; 19 20 namespace Fortran::evaluate { 21 22 // Can x*(a,b) be represented as (x*a,x*b)? This code duplication 23 // of the subexpression "x" cannot (yet?) be reliably undone by 24 // common subexpression elimination in lowering, so it's disabled 25 // here for now to avoid the risk of potential duplication of 26 // expensive subexpressions (e.g., large array expressions, references 27 // to expensive functions) in generate code. 28 static constexpr bool allowOperandDuplication{false}; 29 30 std::optional<Expr<SomeType>> AsGenericExpr(DataRef &&ref) { 31 if (auto dyType{DynamicType::From(ref.GetLastSymbol())}) { 32 return TypedWrapper<Designator, DataRef>(*dyType, std::move(ref)); 33 } else { 34 return std::nullopt; 35 } 36 } 37 38 std::optional<Expr<SomeType>> AsGenericExpr(const Symbol &symbol) { 39 return AsGenericExpr(DataRef{symbol}); 40 } 41 42 Expr<SomeType> Parenthesize(Expr<SomeType> &&expr) { 43 return common::visit( 44 [&](auto &&x) { 45 using T = std::decay_t<decltype(x)>; 46 if constexpr (common::HasMember<T, TypelessExpression>) { 47 return expr; // no parentheses around typeless 48 } else if constexpr (std::is_same_v<T, Expr<SomeDerived>>) { 49 return AsGenericExpr(Parentheses<SomeDerived>{std::move(x)}); 50 } else { 51 return common::visit( 52 [](auto &&y) { 53 using T = ResultType<decltype(y)>; 54 return AsGenericExpr(Parentheses<T>{std::move(y)}); 55 }, 56 std::move(x.u)); 57 } 58 }, 59 std::move(expr.u)); 60 } 61 62 std::optional<DataRef> ExtractDataRef( 63 const ActualArgument &arg, bool intoSubstring, bool intoComplexPart) { 64 return ExtractDataRef(arg.UnwrapExpr(), intoSubstring, intoComplexPart); 65 } 66 67 std::optional<DataRef> ExtractSubstringBase(const Substring &substring) { 68 return common::visit( 69 common::visitors{ 70 [&](const DataRef &x) -> std::optional<DataRef> { return x; }, 71 [&](const StaticDataObject::Pointer &) -> std::optional<DataRef> { 72 return std::nullopt; 73 }, 74 }, 75 substring.parent()); 76 } 77 78 // IsVariable() 79 80 auto IsVariableHelper::operator()(const Symbol &symbol) const -> Result { 81 // ASSOCIATE(x => expr) -- x counts as a variable, but undefinable 82 const Symbol &ultimate{symbol.GetUltimate()}; 83 return !IsNamedConstant(ultimate) && 84 (ultimate.has<semantics::ObjectEntityDetails>() || 85 (ultimate.has<semantics::EntityDetails>() && 86 ultimate.attrs().test(semantics::Attr::TARGET)) || 87 ultimate.has<semantics::AssocEntityDetails>()); 88 } 89 auto IsVariableHelper::operator()(const Component &x) const -> Result { 90 const Symbol &comp{x.GetLastSymbol()}; 91 return (*this)(comp) && (IsPointer(comp) || (*this)(x.base())); 92 } 93 auto IsVariableHelper::operator()(const ArrayRef &x) const -> Result { 94 return (*this)(x.base()); 95 } 96 auto IsVariableHelper::operator()(const Substring &x) const -> Result { 97 return (*this)(x.GetBaseObject()); 98 } 99 auto IsVariableHelper::operator()(const ProcedureDesignator &x) const 100 -> Result { 101 if (const Symbol * symbol{x.GetSymbol()}) { 102 const Symbol *result{FindFunctionResult(*symbol)}; 103 return result && IsPointer(*result) && !IsProcedurePointer(*result); 104 } 105 return false; 106 } 107 108 // Conversions of COMPLEX component expressions to REAL. 109 ConvertRealOperandsResult ConvertRealOperands( 110 parser::ContextualMessages &messages, Expr<SomeType> &&x, 111 Expr<SomeType> &&y, int defaultRealKind) { 112 return common::visit( 113 common::visitors{ 114 [&](Expr<SomeInteger> &&ix, 115 Expr<SomeInteger> &&iy) -> ConvertRealOperandsResult { 116 // Can happen in a CMPLX() constructor. Per F'2018, 117 // both integer operands are converted to default REAL. 118 return {AsSameKindExprs<TypeCategory::Real>( 119 ConvertToKind<TypeCategory::Real>( 120 defaultRealKind, std::move(ix)), 121 ConvertToKind<TypeCategory::Real>( 122 defaultRealKind, std::move(iy)))}; 123 }, 124 [&](Expr<SomeInteger> &&ix, 125 Expr<SomeReal> &&ry) -> ConvertRealOperandsResult { 126 return {AsSameKindExprs<TypeCategory::Real>( 127 ConvertTo(ry, std::move(ix)), std::move(ry))}; 128 }, 129 [&](Expr<SomeReal> &&rx, 130 Expr<SomeInteger> &&iy) -> ConvertRealOperandsResult { 131 return {AsSameKindExprs<TypeCategory::Real>( 132 std::move(rx), ConvertTo(rx, std::move(iy)))}; 133 }, 134 [&](Expr<SomeReal> &&rx, 135 Expr<SomeReal> &&ry) -> ConvertRealOperandsResult { 136 return {AsSameKindExprs<TypeCategory::Real>( 137 std::move(rx), std::move(ry))}; 138 }, 139 [&](Expr<SomeInteger> &&ix, 140 BOZLiteralConstant &&by) -> ConvertRealOperandsResult { 141 return {AsSameKindExprs<TypeCategory::Real>( 142 ConvertToKind<TypeCategory::Real>( 143 defaultRealKind, std::move(ix)), 144 ConvertToKind<TypeCategory::Real>( 145 defaultRealKind, std::move(by)))}; 146 }, 147 [&](BOZLiteralConstant &&bx, 148 Expr<SomeInteger> &&iy) -> ConvertRealOperandsResult { 149 return {AsSameKindExprs<TypeCategory::Real>( 150 ConvertToKind<TypeCategory::Real>( 151 defaultRealKind, std::move(bx)), 152 ConvertToKind<TypeCategory::Real>( 153 defaultRealKind, std::move(iy)))}; 154 }, 155 [&](Expr<SomeReal> &&rx, 156 BOZLiteralConstant &&by) -> ConvertRealOperandsResult { 157 return {AsSameKindExprs<TypeCategory::Real>( 158 std::move(rx), ConvertTo(rx, std::move(by)))}; 159 }, 160 [&](BOZLiteralConstant &&bx, 161 Expr<SomeReal> &&ry) -> ConvertRealOperandsResult { 162 return {AsSameKindExprs<TypeCategory::Real>( 163 ConvertTo(ry, std::move(bx)), std::move(ry))}; 164 }, 165 [&](auto &&, auto &&) -> ConvertRealOperandsResult { // C718 166 messages.Say("operands must be INTEGER or REAL"_err_en_US); 167 return std::nullopt; 168 }, 169 }, 170 std::move(x.u), std::move(y.u)); 171 } 172 173 // Helpers for NumericOperation and its subroutines below. 174 static std::optional<Expr<SomeType>> NoExpr() { return std::nullopt; } 175 176 template <TypeCategory CAT> 177 std::optional<Expr<SomeType>> Package(Expr<SomeKind<CAT>> &&catExpr) { 178 return {AsGenericExpr(std::move(catExpr))}; 179 } 180 template <TypeCategory CAT> 181 std::optional<Expr<SomeType>> Package( 182 std::optional<Expr<SomeKind<CAT>>> &&catExpr) { 183 if (catExpr) { 184 return {AsGenericExpr(std::move(*catExpr))}; 185 } else { 186 return std::nullopt; 187 } 188 } 189 190 // Mixed REAL+INTEGER operations. REAL**INTEGER is a special case that 191 // does not require conversion of the exponent expression. 192 template <template <typename> class OPR> 193 std::optional<Expr<SomeType>> MixedRealLeft( 194 Expr<SomeReal> &&rx, Expr<SomeInteger> &&iy) { 195 return Package(common::visit( 196 [&](auto &&rxk) -> Expr<SomeReal> { 197 using resultType = ResultType<decltype(rxk)>; 198 if constexpr (std::is_same_v<OPR<resultType>, Power<resultType>>) { 199 return AsCategoryExpr( 200 RealToIntPower<resultType>{std::move(rxk), std::move(iy)}); 201 } 202 // G++ 8.1.0 emits bogus warnings about missing return statements if 203 // this statement is wrapped in an "else", as it should be. 204 return AsCategoryExpr(OPR<resultType>{ 205 std::move(rxk), ConvertToType<resultType>(std::move(iy))}); 206 }, 207 std::move(rx.u))); 208 } 209 210 template <int KIND> 211 Expr<SomeComplex> MakeComplex(Expr<Type<TypeCategory::Real, KIND>> &&re, 212 Expr<Type<TypeCategory::Real, KIND>> &&im) { 213 return AsCategoryExpr(ComplexConstructor<KIND>{std::move(re), std::move(im)}); 214 } 215 216 std::optional<Expr<SomeComplex>> ConstructComplex( 217 parser::ContextualMessages &messages, Expr<SomeType> &&real, 218 Expr<SomeType> &&imaginary, int defaultRealKind) { 219 if (auto converted{ConvertRealOperands( 220 messages, std::move(real), std::move(imaginary), defaultRealKind)}) { 221 return {common::visit( 222 [](auto &&pair) { 223 return MakeComplex(std::move(pair[0]), std::move(pair[1])); 224 }, 225 std::move(*converted))}; 226 } 227 return std::nullopt; 228 } 229 230 std::optional<Expr<SomeComplex>> ConstructComplex( 231 parser::ContextualMessages &messages, std::optional<Expr<SomeType>> &&real, 232 std::optional<Expr<SomeType>> &&imaginary, int defaultRealKind) { 233 if (auto parts{common::AllPresent(std::move(real), std::move(imaginary))}) { 234 return ConstructComplex(messages, std::get<0>(std::move(*parts)), 235 std::get<1>(std::move(*parts)), defaultRealKind); 236 } 237 return std::nullopt; 238 } 239 240 // Extracts the real or imaginary part of the result of a COMPLEX 241 // expression, when that expression is simple enough to be duplicated. 242 template <bool GET_IMAGINARY> struct ComplexPartExtractor { 243 template <typename A> static std::optional<Expr<SomeReal>> Get(const A &) { 244 return std::nullopt; 245 } 246 247 template <int KIND> 248 static std::optional<Expr<SomeReal>> Get( 249 const Parentheses<Type<TypeCategory::Complex, KIND>> &kz) { 250 if (auto x{Get(kz.left())}) { 251 return AsGenericExpr(AsSpecificExpr( 252 Parentheses<Type<TypeCategory::Real, KIND>>{std::move(*x)})); 253 } else { 254 return std::nullopt; 255 } 256 } 257 258 template <int KIND> 259 static std::optional<Expr<SomeReal>> Get( 260 const Negate<Type<TypeCategory::Complex, KIND>> &kz) { 261 if (auto x{Get(kz.left())}) { 262 return AsGenericExpr(AsSpecificExpr( 263 Negate<Type<TypeCategory::Real, KIND>>{std::move(*x)})); 264 } else { 265 return std::nullopt; 266 } 267 } 268 269 template <int KIND> 270 static std::optional<Expr<SomeReal>> Get( 271 const Convert<Type<TypeCategory::Complex, KIND>, TypeCategory::Complex> 272 &kz) { 273 if (auto x{Get(kz.left())}) { 274 return AsGenericExpr(AsSpecificExpr( 275 Convert<Type<TypeCategory::Real, KIND>, TypeCategory::Real>{ 276 AsGenericExpr(std::move(*x))})); 277 } else { 278 return std::nullopt; 279 } 280 } 281 282 template <int KIND> 283 static std::optional<Expr<SomeReal>> Get(const ComplexConstructor<KIND> &kz) { 284 return GET_IMAGINARY ? Get(kz.right()) : Get(kz.left()); 285 } 286 287 template <int KIND> 288 static std::optional<Expr<SomeReal>> Get( 289 const Constant<Type<TypeCategory::Complex, KIND>> &kz) { 290 if (auto cz{kz.GetScalarValue()}) { 291 return AsGenericExpr( 292 AsSpecificExpr(GET_IMAGINARY ? cz->AIMAG() : cz->REAL())); 293 } else { 294 return std::nullopt; 295 } 296 } 297 298 template <int KIND> 299 static std::optional<Expr<SomeReal>> Get( 300 const Designator<Type<TypeCategory::Complex, KIND>> &kz) { 301 if (const auto *symbolRef{std::get_if<SymbolRef>(&kz.u)}) { 302 return AsGenericExpr(AsSpecificExpr( 303 Designator<Type<TypeCategory::Complex, KIND>>{ComplexPart{ 304 DataRef{*symbolRef}, 305 GET_IMAGINARY ? ComplexPart::Part::IM : ComplexPart::Part::RE}})); 306 } else { 307 return std::nullopt; 308 } 309 } 310 311 template <int KIND> 312 static std::optional<Expr<SomeReal>> Get( 313 const Expr<Type<TypeCategory::Complex, KIND>> &kz) { 314 return Get(kz.u); 315 } 316 317 static std::optional<Expr<SomeReal>> Get(const Expr<SomeComplex> &z) { 318 return Get(z.u); 319 } 320 }; 321 322 // Convert REAL to COMPLEX of the same kind. Preserving the real operand kind 323 // and then applying complex operand promotion rules allows the result to have 324 // the highest precision of REAL and COMPLEX operands as required by Fortran 325 // 2018 10.9.1.3. 326 Expr<SomeComplex> PromoteRealToComplex(Expr<SomeReal> &&someX) { 327 return common::visit( 328 [](auto &&x) { 329 using RT = ResultType<decltype(x)>; 330 return AsCategoryExpr(ComplexConstructor<RT::kind>{ 331 std::move(x), AsExpr(Constant<RT>{Scalar<RT>{}})}); 332 }, 333 std::move(someX.u)); 334 } 335 336 // Handle mixed COMPLEX+REAL (or INTEGER) operations in a better way 337 // than just converting the second operand to COMPLEX and performing the 338 // corresponding COMPLEX+COMPLEX operation. 339 template <template <typename> class OPR, TypeCategory RCAT> 340 std::optional<Expr<SomeType>> MixedComplexLeft( 341 parser::ContextualMessages &messages, const Expr<SomeComplex> &zx, 342 const Expr<SomeKind<RCAT>> &iry, [[maybe_unused]] int defaultRealKind) { 343 if constexpr (RCAT == TypeCategory::Integer && 344 std::is_same_v<OPR<LargestReal>, Power<LargestReal>>) { 345 // COMPLEX**INTEGER is a special case that doesn't convert the exponent. 346 return Package(common::visit( 347 [&](const auto &zxk) { 348 using Ty = ResultType<decltype(zxk)>; 349 return AsCategoryExpr(AsExpr( 350 RealToIntPower<Ty>{common::Clone(zxk), common::Clone(iry)})); 351 }, 352 zx.u)); 353 } 354 std::optional<Expr<SomeReal>> zr{ComplexPartExtractor<false>{}.Get(zx)}; 355 std::optional<Expr<SomeReal>> zi{ComplexPartExtractor<true>{}.Get(zx)}; 356 if (!zr || !zi) { 357 } else if constexpr (std::is_same_v<OPR<LargestReal>, Add<LargestReal>> || 358 std::is_same_v<OPR<LargestReal>, Subtract<LargestReal>>) { 359 // (a,b) + x -> (a+x, b) 360 // (a,b) - x -> (a-x, b) 361 if (std::optional<Expr<SomeType>> rr{ 362 NumericOperation<OPR>(messages, AsGenericExpr(std::move(*zr)), 363 AsGenericExpr(common::Clone(iry)), defaultRealKind)}) { 364 return Package(ConstructComplex(messages, std::move(*rr), 365 AsGenericExpr(std::move(*zi)), defaultRealKind)); 366 } 367 } else if constexpr (allowOperandDuplication && 368 (std::is_same_v<OPR<LargestReal>, Multiply<LargestReal>> || 369 std::is_same_v<OPR<LargestReal>, Divide<LargestReal>>)) { 370 // (a,b) * x -> (a*x, b*x) 371 // (a,b) / x -> (a/x, b/x) 372 auto copy{iry}; 373 auto rr{NumericOperation<OPR>(messages, AsGenericExpr(std::move(*zr)), 374 AsGenericExpr(common::Clone(iry)), defaultRealKind)}; 375 auto ri{NumericOperation<OPR>(messages, AsGenericExpr(std::move(*zi)), 376 AsGenericExpr(std::move(copy)), defaultRealKind)}; 377 if (auto parts{common::AllPresent(std::move(rr), std::move(ri))}) { 378 return Package(ConstructComplex(messages, std::get<0>(std::move(*parts)), 379 std::get<1>(std::move(*parts)), defaultRealKind)); 380 } 381 } 382 return std::nullopt; 383 } 384 385 // Mixed COMPLEX operations with the COMPLEX operand on the right. 386 // x + (a,b) -> (x+a, b) 387 // x - (a,b) -> (x-a, -b) 388 // x * (a,b) -> (x*a, x*b) 389 // x / (a,b) -> (x,0) / (a,b) (and **) 390 template <template <typename> class OPR, TypeCategory LCAT> 391 std::optional<Expr<SomeType>> MixedComplexRight( 392 parser::ContextualMessages &messages, const Expr<SomeKind<LCAT>> &irx, 393 const Expr<SomeComplex> &zy, [[maybe_unused]] int defaultRealKind) { 394 if constexpr (std::is_same_v<OPR<LargestReal>, Add<LargestReal>>) { 395 // x + (a,b) -> (a,b) + x -> (a+x, b) 396 return MixedComplexLeft<OPR, LCAT>(messages, zy, irx, defaultRealKind); 397 } else if constexpr (allowOperandDuplication && 398 std::is_same_v<OPR<LargestReal>, Multiply<LargestReal>>) { 399 // x * (a,b) -> (a,b) * x -> (a*x, b*x) 400 return MixedComplexLeft<OPR, LCAT>(messages, zy, irx, defaultRealKind); 401 } else if constexpr (std::is_same_v<OPR<LargestReal>, 402 Subtract<LargestReal>>) { 403 // x - (a,b) -> (x-a, -b) 404 std::optional<Expr<SomeReal>> zr{ComplexPartExtractor<false>{}.Get(zy)}; 405 std::optional<Expr<SomeReal>> zi{ComplexPartExtractor<true>{}.Get(zy)}; 406 if (zr && zi) { 407 if (std::optional<Expr<SomeType>> rr{NumericOperation<Subtract>(messages, 408 AsGenericExpr(common::Clone(irx)), AsGenericExpr(std::move(*zr)), 409 defaultRealKind)}) { 410 return Package(ConstructComplex(messages, std::move(*rr), 411 AsGenericExpr(-std::move(*zi)), defaultRealKind)); 412 } 413 } 414 } 415 return std::nullopt; 416 } 417 418 // Promotes REAL(rk) and COMPLEX(zk) operands COMPLEX(max(rk,zk)) 419 // then combine them with an operator. 420 template <template <typename> class OPR, TypeCategory XCAT, TypeCategory YCAT> 421 Expr<SomeComplex> PromoteMixedComplexReal( 422 Expr<SomeKind<XCAT>> &&x, Expr<SomeKind<YCAT>> &&y) { 423 static_assert(XCAT == TypeCategory::Complex || YCAT == TypeCategory::Complex); 424 static_assert(XCAT == TypeCategory::Real || YCAT == TypeCategory::Real); 425 return common::visit( 426 [&](const auto &kx, const auto &ky) { 427 constexpr int maxKind{std::max( 428 ResultType<decltype(kx)>::kind, ResultType<decltype(ky)>::kind)}; 429 using ZTy = Type<TypeCategory::Complex, maxKind>; 430 return Expr<SomeComplex>{ 431 Expr<ZTy>{OPR<ZTy>{ConvertToType<ZTy>(std::move(x)), 432 ConvertToType<ZTy>(std::move(y))}}}; 433 }, 434 x.u, y.u); 435 } 436 437 // N.B. When a "typeless" BOZ literal constant appears as one (not both!) of 438 // the operands to a dyadic operation where one is permitted, it assumes the 439 // type and kind of the other operand. 440 template <template <typename> class OPR> 441 std::optional<Expr<SomeType>> NumericOperation( 442 parser::ContextualMessages &messages, Expr<SomeType> &&x, 443 Expr<SomeType> &&y, int defaultRealKind) { 444 return common::visit( 445 common::visitors{ 446 [](Expr<SomeInteger> &&ix, Expr<SomeInteger> &&iy) { 447 return Package(PromoteAndCombine<OPR, TypeCategory::Integer>( 448 std::move(ix), std::move(iy))); 449 }, 450 [](Expr<SomeReal> &&rx, Expr<SomeReal> &&ry) { 451 return Package(PromoteAndCombine<OPR, TypeCategory::Real>( 452 std::move(rx), std::move(ry))); 453 }, 454 // Mixed REAL/INTEGER operations 455 [](Expr<SomeReal> &&rx, Expr<SomeInteger> &&iy) { 456 return MixedRealLeft<OPR>(std::move(rx), std::move(iy)); 457 }, 458 [](Expr<SomeInteger> &&ix, Expr<SomeReal> &&ry) { 459 return Package(common::visit( 460 [&](auto &&ryk) -> Expr<SomeReal> { 461 using resultType = ResultType<decltype(ryk)>; 462 return AsCategoryExpr( 463 OPR<resultType>{ConvertToType<resultType>(std::move(ix)), 464 std::move(ryk)}); 465 }, 466 std::move(ry.u))); 467 }, 468 // Homogeneous and mixed COMPLEX operations 469 [](Expr<SomeComplex> &&zx, Expr<SomeComplex> &&zy) { 470 return Package(PromoteAndCombine<OPR, TypeCategory::Complex>( 471 std::move(zx), std::move(zy))); 472 }, 473 [&](Expr<SomeComplex> &&zx, Expr<SomeInteger> &&iy) { 474 if (auto result{ 475 MixedComplexLeft<OPR>(messages, zx, iy, defaultRealKind)}) { 476 return result; 477 } else { 478 return Package(PromoteAndCombine<OPR, TypeCategory::Complex>( 479 std::move(zx), ConvertTo(zx, std::move(iy)))); 480 } 481 }, 482 [&](Expr<SomeComplex> &&zx, Expr<SomeReal> &&ry) { 483 if (auto result{ 484 MixedComplexLeft<OPR>(messages, zx, ry, defaultRealKind)}) { 485 return result; 486 } else { 487 return Package( 488 PromoteMixedComplexReal<OPR>(std::move(zx), std::move(ry))); 489 } 490 }, 491 [&](Expr<SomeInteger> &&ix, Expr<SomeComplex> &&zy) { 492 if (auto result{MixedComplexRight<OPR>( 493 messages, ix, zy, defaultRealKind)}) { 494 return result; 495 } else { 496 return Package(PromoteAndCombine<OPR, TypeCategory::Complex>( 497 ConvertTo(zy, std::move(ix)), std::move(zy))); 498 } 499 }, 500 [&](Expr<SomeReal> &&rx, Expr<SomeComplex> &&zy) { 501 if (auto result{MixedComplexRight<OPR>( 502 messages, rx, zy, defaultRealKind)}) { 503 return result; 504 } else { 505 return Package( 506 PromoteMixedComplexReal<OPR>(std::move(rx), std::move(zy))); 507 } 508 }, 509 // Operations with one typeless operand 510 [&](BOZLiteralConstant &&bx, Expr<SomeInteger> &&iy) { 511 return NumericOperation<OPR>(messages, 512 AsGenericExpr(ConvertTo(iy, std::move(bx))), std::move(y), 513 defaultRealKind); 514 }, 515 [&](BOZLiteralConstant &&bx, Expr<SomeReal> &&ry) { 516 return NumericOperation<OPR>(messages, 517 AsGenericExpr(ConvertTo(ry, std::move(bx))), std::move(y), 518 defaultRealKind); 519 }, 520 [&](Expr<SomeInteger> &&ix, BOZLiteralConstant &&by) { 521 return NumericOperation<OPR>(messages, std::move(x), 522 AsGenericExpr(ConvertTo(ix, std::move(by))), defaultRealKind); 523 }, 524 [&](Expr<SomeReal> &&rx, BOZLiteralConstant &&by) { 525 return NumericOperation<OPR>(messages, std::move(x), 526 AsGenericExpr(ConvertTo(rx, std::move(by))), defaultRealKind); 527 }, 528 // Default case 529 [&](auto &&, auto &&) { 530 messages.Say("non-numeric operands to numeric operation"_err_en_US); 531 return NoExpr(); 532 }, 533 }, 534 std::move(x.u), std::move(y.u)); 535 } 536 537 template std::optional<Expr<SomeType>> NumericOperation<Power>( 538 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&, 539 int defaultRealKind); 540 template std::optional<Expr<SomeType>> NumericOperation<Multiply>( 541 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&, 542 int defaultRealKind); 543 template std::optional<Expr<SomeType>> NumericOperation<Divide>( 544 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&, 545 int defaultRealKind); 546 template std::optional<Expr<SomeType>> NumericOperation<Add>( 547 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&, 548 int defaultRealKind); 549 template std::optional<Expr<SomeType>> NumericOperation<Subtract>( 550 parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&, 551 int defaultRealKind); 552 553 std::optional<Expr<SomeType>> Negation( 554 parser::ContextualMessages &messages, Expr<SomeType> &&x) { 555 return common::visit( 556 common::visitors{ 557 [&](BOZLiteralConstant &&) { 558 messages.Say("BOZ literal cannot be negated"_err_en_US); 559 return NoExpr(); 560 }, 561 [&](NullPointer &&) { 562 messages.Say("NULL() cannot be negated"_err_en_US); 563 return NoExpr(); 564 }, 565 [&](ProcedureDesignator &&) { 566 messages.Say("Subroutine cannot be negated"_err_en_US); 567 return NoExpr(); 568 }, 569 [&](ProcedureRef &&) { 570 messages.Say("Pointer to subroutine cannot be negated"_err_en_US); 571 return NoExpr(); 572 }, 573 [&](Expr<SomeInteger> &&x) { return Package(-std::move(x)); }, 574 [&](Expr<SomeReal> &&x) { return Package(-std::move(x)); }, 575 [&](Expr<SomeComplex> &&x) { return Package(-std::move(x)); }, 576 [&](Expr<SomeCharacter> &&) { 577 messages.Say("CHARACTER cannot be negated"_err_en_US); 578 return NoExpr(); 579 }, 580 [&](Expr<SomeLogical> &&) { 581 messages.Say("LOGICAL cannot be negated"_err_en_US); 582 return NoExpr(); 583 }, 584 [&](Expr<SomeDerived> &&) { 585 messages.Say("Operand cannot be negated"_err_en_US); 586 return NoExpr(); 587 }, 588 }, 589 std::move(x.u)); 590 } 591 592 Expr<SomeLogical> LogicalNegation(Expr<SomeLogical> &&x) { 593 return common::visit( 594 [](auto &&xk) { return AsCategoryExpr(LogicalNegation(std::move(xk))); }, 595 std::move(x.u)); 596 } 597 598 template <TypeCategory CAT> 599 Expr<LogicalResult> PromoteAndRelate( 600 RelationalOperator opr, Expr<SomeKind<CAT>> &&x, Expr<SomeKind<CAT>> &&y) { 601 return common::visit( 602 [=](auto &&xy) { 603 return PackageRelation(opr, std::move(xy[0]), std::move(xy[1])); 604 }, 605 AsSameKindExprs(std::move(x), std::move(y))); 606 } 607 608 std::optional<Expr<LogicalResult>> Relate(parser::ContextualMessages &messages, 609 RelationalOperator opr, Expr<SomeType> &&x, Expr<SomeType> &&y) { 610 return common::visit( 611 common::visitors{ 612 [=](Expr<SomeInteger> &&ix, 613 Expr<SomeInteger> &&iy) -> std::optional<Expr<LogicalResult>> { 614 return PromoteAndRelate(opr, std::move(ix), std::move(iy)); 615 }, 616 [=](Expr<SomeReal> &&rx, 617 Expr<SomeReal> &&ry) -> std::optional<Expr<LogicalResult>> { 618 return PromoteAndRelate(opr, std::move(rx), std::move(ry)); 619 }, 620 [&](Expr<SomeReal> &&rx, Expr<SomeInteger> &&iy) { 621 return Relate(messages, opr, std::move(x), 622 AsGenericExpr(ConvertTo(rx, std::move(iy)))); 623 }, 624 [&](Expr<SomeInteger> &&ix, Expr<SomeReal> &&ry) { 625 return Relate(messages, opr, 626 AsGenericExpr(ConvertTo(ry, std::move(ix))), std::move(y)); 627 }, 628 [&](Expr<SomeComplex> &&zx, 629 Expr<SomeComplex> &&zy) -> std::optional<Expr<LogicalResult>> { 630 if (opr == RelationalOperator::EQ || 631 opr == RelationalOperator::NE) { 632 return PromoteAndRelate(opr, std::move(zx), std::move(zy)); 633 } else { 634 messages.Say( 635 "COMPLEX data may be compared only for equality"_err_en_US); 636 return std::nullopt; 637 } 638 }, 639 [&](Expr<SomeComplex> &&zx, Expr<SomeInteger> &&iy) { 640 return Relate(messages, opr, std::move(x), 641 AsGenericExpr(ConvertTo(zx, std::move(iy)))); 642 }, 643 [&](Expr<SomeComplex> &&zx, Expr<SomeReal> &&ry) { 644 return Relate(messages, opr, std::move(x), 645 AsGenericExpr(ConvertTo(zx, std::move(ry)))); 646 }, 647 [&](Expr<SomeInteger> &&ix, Expr<SomeComplex> &&zy) { 648 return Relate(messages, opr, 649 AsGenericExpr(ConvertTo(zy, std::move(ix))), std::move(y)); 650 }, 651 [&](Expr<SomeReal> &&rx, Expr<SomeComplex> &&zy) { 652 return Relate(messages, opr, 653 AsGenericExpr(ConvertTo(zy, std::move(rx))), std::move(y)); 654 }, 655 [&](Expr<SomeCharacter> &&cx, Expr<SomeCharacter> &&cy) { 656 return common::visit( 657 [&](auto &&cxk, 658 auto &&cyk) -> std::optional<Expr<LogicalResult>> { 659 using Ty = ResultType<decltype(cxk)>; 660 if constexpr (std::is_same_v<Ty, ResultType<decltype(cyk)>>) { 661 return PackageRelation(opr, std::move(cxk), std::move(cyk)); 662 } else { 663 messages.Say( 664 "CHARACTER operands do not have same KIND"_err_en_US); 665 return std::nullopt; 666 } 667 }, 668 std::move(cx.u), std::move(cy.u)); 669 }, 670 // Default case 671 [&](auto &&, auto &&) { 672 DIE("invalid types for relational operator"); 673 return std::optional<Expr<LogicalResult>>{}; 674 }, 675 }, 676 std::move(x.u), std::move(y.u)); 677 } 678 679 Expr<SomeLogical> BinaryLogicalOperation( 680 LogicalOperator opr, Expr<SomeLogical> &&x, Expr<SomeLogical> &&y) { 681 CHECK(opr != LogicalOperator::Not); 682 return common::visit( 683 [=](auto &&xy) { 684 using Ty = ResultType<decltype(xy[0])>; 685 return Expr<SomeLogical>{BinaryLogicalOperation<Ty::kind>( 686 opr, std::move(xy[0]), std::move(xy[1]))}; 687 }, 688 AsSameKindExprs(std::move(x), std::move(y))); 689 } 690 691 template <TypeCategory TO> 692 std::optional<Expr<SomeType>> ConvertToNumeric(int kind, Expr<SomeType> &&x) { 693 static_assert(common::IsNumericTypeCategory(TO)); 694 return common::visit( 695 [=](auto &&cx) -> std::optional<Expr<SomeType>> { 696 using cxType = std::decay_t<decltype(cx)>; 697 if constexpr (!common::HasMember<cxType, TypelessExpression>) { 698 if constexpr (IsNumericTypeCategory(ResultType<cxType>::category)) { 699 return Expr<SomeType>{ConvertToKind<TO>(kind, std::move(cx))}; 700 } 701 } 702 return std::nullopt; 703 }, 704 std::move(x.u)); 705 } 706 707 std::optional<Expr<SomeType>> ConvertToType( 708 const DynamicType &type, Expr<SomeType> &&x) { 709 if (type.IsTypelessIntrinsicArgument()) { 710 return std::nullopt; 711 } 712 switch (type.category()) { 713 case TypeCategory::Integer: 714 if (auto *boz{std::get_if<BOZLiteralConstant>(&x.u)}) { 715 // Extension to C7109: allow BOZ literals to appear in integer contexts 716 // when the type is unambiguous. 717 return Expr<SomeType>{ 718 ConvertToKind<TypeCategory::Integer>(type.kind(), std::move(*boz))}; 719 } 720 return ConvertToNumeric<TypeCategory::Integer>(type.kind(), std::move(x)); 721 case TypeCategory::Real: 722 if (auto *boz{std::get_if<BOZLiteralConstant>(&x.u)}) { 723 return Expr<SomeType>{ 724 ConvertToKind<TypeCategory::Real>(type.kind(), std::move(*boz))}; 725 } 726 return ConvertToNumeric<TypeCategory::Real>(type.kind(), std::move(x)); 727 case TypeCategory::Complex: 728 return ConvertToNumeric<TypeCategory::Complex>(type.kind(), std::move(x)); 729 case TypeCategory::Character: 730 if (auto *cx{UnwrapExpr<Expr<SomeCharacter>>(x)}) { 731 auto converted{ 732 ConvertToKind<TypeCategory::Character>(type.kind(), std::move(*cx))}; 733 if (auto length{type.GetCharLength()}) { 734 converted = common::visit( 735 [&](auto &&x) { 736 using CharacterType = ResultType<decltype(x)>; 737 return Expr<SomeCharacter>{ 738 Expr<CharacterType>{SetLength<CharacterType::kind>{ 739 std::move(x), std::move(*length)}}}; 740 }, 741 std::move(converted.u)); 742 } 743 return Expr<SomeType>{std::move(converted)}; 744 } 745 break; 746 case TypeCategory::Logical: 747 if (auto *cx{UnwrapExpr<Expr<SomeLogical>>(x)}) { 748 return Expr<SomeType>{ 749 ConvertToKind<TypeCategory::Logical>(type.kind(), std::move(*cx))}; 750 } 751 break; 752 case TypeCategory::Derived: 753 if (auto fromType{x.GetType()}) { 754 if (type.IsTkCompatibleWith(*fromType)) { 755 // "x" could be assigned or passed to "type", or appear in a 756 // structure constructor as a value for a component with "type" 757 return std::move(x); 758 } 759 } 760 break; 761 } 762 return std::nullopt; 763 } 764 765 std::optional<Expr<SomeType>> ConvertToType( 766 const DynamicType &to, std::optional<Expr<SomeType>> &&x) { 767 if (x) { 768 return ConvertToType(to, std::move(*x)); 769 } else { 770 return std::nullopt; 771 } 772 } 773 774 std::optional<Expr<SomeType>> ConvertToType( 775 const Symbol &symbol, Expr<SomeType> &&x) { 776 if (auto symType{DynamicType::From(symbol)}) { 777 return ConvertToType(*symType, std::move(x)); 778 } 779 return std::nullopt; 780 } 781 782 std::optional<Expr<SomeType>> ConvertToType( 783 const Symbol &to, std::optional<Expr<SomeType>> &&x) { 784 if (x) { 785 return ConvertToType(to, std::move(*x)); 786 } else { 787 return std::nullopt; 788 } 789 } 790 791 bool IsAssumedRank(const Symbol &original) { 792 if (const auto *assoc{original.detailsIf<semantics::AssocEntityDetails>()}) { 793 if (assoc->rank()) { 794 return false; // in RANK(n) or RANK(*) 795 } else if (assoc->IsAssumedRank()) { 796 return true; // RANK DEFAULT 797 } 798 } 799 const Symbol &symbol{semantics::ResolveAssociations(original)}; 800 const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()}; 801 return object && object->IsAssumedRank(); 802 } 803 804 bool IsAssumedRank(const ActualArgument &arg) { 805 if (const auto *expr{arg.UnwrapExpr()}) { 806 return IsAssumedRank(*expr); 807 } else { 808 const Symbol *assumedTypeDummy{arg.GetAssumedTypeDummy()}; 809 CHECK(assumedTypeDummy); 810 return IsAssumedRank(*assumedTypeDummy); 811 } 812 } 813 814 bool IsCoarray(const ActualArgument &arg) { 815 const auto *expr{arg.UnwrapExpr()}; 816 return expr && IsCoarray(*expr); 817 } 818 819 bool IsCoarray(const Symbol &symbol) { 820 return GetAssociationRoot(symbol).Corank() > 0; 821 } 822 823 bool IsProcedureDesignator(const Expr<SomeType> &expr) { 824 return std::holds_alternative<ProcedureDesignator>(expr.u); 825 } 826 bool IsFunctionDesignator(const Expr<SomeType> &expr) { 827 const auto *designator{std::get_if<ProcedureDesignator>(&expr.u)}; 828 return designator && designator->GetType().has_value(); 829 } 830 831 bool IsPointer(const Expr<SomeType> &expr) { 832 return IsObjectPointer(expr) || IsProcedurePointer(expr); 833 } 834 835 bool IsProcedurePointer(const Expr<SomeType> &expr) { 836 if (IsNullProcedurePointer(expr)) { 837 return true; 838 } else if (const auto *funcRef{UnwrapProcedureRef(expr)}) { 839 if (const Symbol * proc{funcRef->proc().GetSymbol()}) { 840 const Symbol *result{FindFunctionResult(*proc)}; 841 return result && IsProcedurePointer(*result); 842 } else { 843 return false; 844 } 845 } else if (const auto *proc{std::get_if<ProcedureDesignator>(&expr.u)}) { 846 return IsProcedurePointer(proc->GetSymbol()); 847 } else { 848 return false; 849 } 850 } 851 852 bool IsProcedure(const Expr<SomeType> &expr) { 853 return IsProcedureDesignator(expr) || IsProcedurePointer(expr); 854 } 855 856 bool IsProcedurePointerTarget(const Expr<SomeType> &expr) { 857 return common::visit(common::visitors{ 858 [](const NullPointer &) { return true; }, 859 [](const ProcedureDesignator &) { return true; }, 860 [](const ProcedureRef &) { return true; }, 861 [&](const auto &) { 862 const Symbol *last{GetLastSymbol(expr)}; 863 return last && IsProcedurePointer(*last); 864 }, 865 }, 866 expr.u); 867 } 868 869 bool IsObjectPointer(const Expr<SomeType> &expr) { 870 if (IsNullObjectPointer(expr)) { 871 return true; 872 } else if (IsProcedurePointerTarget(expr)) { 873 return false; 874 } else if (const auto *funcRef{UnwrapProcedureRef(expr)}) { 875 return IsVariable(*funcRef); 876 } else if (const Symbol * symbol{UnwrapWholeSymbolOrComponentDataRef(expr)}) { 877 return IsPointer(symbol->GetUltimate()); 878 } else { 879 return false; 880 } 881 } 882 883 // IsNullPointer() & variations 884 885 template <bool IS_PROC_PTR> struct IsNullPointerHelper { 886 template <typename A> bool operator()(const A &) const { return false; } 887 bool operator()(const ProcedureRef &call) const { 888 if constexpr (IS_PROC_PTR) { 889 const auto *intrinsic{call.proc().GetSpecificIntrinsic()}; 890 return intrinsic && 891 intrinsic->characteristics.value().attrs.test( 892 characteristics::Procedure::Attr::NullPointer); 893 } else { 894 return false; 895 } 896 } 897 template <typename T> bool operator()(const FunctionRef<T> &call) const { 898 if constexpr (IS_PROC_PTR) { 899 return false; 900 } else { 901 const auto *intrinsic{call.proc().GetSpecificIntrinsic()}; 902 return intrinsic && 903 intrinsic->characteristics.value().attrs.test( 904 characteristics::Procedure::Attr::NullPointer); 905 } 906 } 907 template <typename T> bool operator()(const Designator<T> &x) const { 908 if (const auto *component{std::get_if<Component>(&x.u)}) { 909 if (const auto *baseSym{std::get_if<SymbolRef>(&component->base().u)}) { 910 const Symbol &base{**baseSym}; 911 if (const auto *object{ 912 base.detailsIf<semantics::ObjectEntityDetails>()}) { 913 // TODO: nested component and array references 914 if (IsNamedConstant(base) && object->init()) { 915 if (auto structCons{ 916 GetScalarConstantValue<SomeDerived>(*object->init())}) { 917 auto iter{structCons->values().find(component->GetLastSymbol())}; 918 if (iter != structCons->values().end()) { 919 return (*this)(iter->second.value()); 920 } 921 } 922 } 923 } 924 } 925 } 926 return false; 927 } 928 bool operator()(const NullPointer &) const { return true; } 929 template <typename T> bool operator()(const Parentheses<T> &x) const { 930 return (*this)(x.left()); 931 } 932 template <typename T> bool operator()(const Expr<T> &x) const { 933 return common::visit(*this, x.u); 934 } 935 }; 936 937 bool IsNullObjectPointer(const Expr<SomeType> &expr) { 938 return IsNullPointerHelper<false>{}(expr); 939 } 940 941 bool IsNullProcedurePointer(const Expr<SomeType> &expr) { 942 return IsNullPointerHelper<true>{}(expr); 943 } 944 945 bool IsNullPointer(const Expr<SomeType> &expr) { 946 return IsNullObjectPointer(expr) || IsNullProcedurePointer(expr); 947 } 948 949 bool IsBareNullPointer(const Expr<SomeType> *expr) { 950 return expr && std::holds_alternative<NullPointer>(expr->u); 951 } 952 953 // GetSymbolVector() 954 auto GetSymbolVectorHelper::operator()(const Symbol &x) const -> Result { 955 if (const auto *details{x.detailsIf<semantics::AssocEntityDetails>()}) { 956 if (IsVariable(details->expr()) && !UnwrapProcedureRef(*details->expr())) { 957 // associate(x => variable that is not a pointer returned by a function) 958 return (*this)(details->expr()); 959 } 960 } 961 return {x.GetUltimate()}; 962 } 963 auto GetSymbolVectorHelper::operator()(const Component &x) const -> Result { 964 Result result{(*this)(x.base())}; 965 result.emplace_back(x.GetLastSymbol()); 966 return result; 967 } 968 auto GetSymbolVectorHelper::operator()(const ArrayRef &x) const -> Result { 969 return GetSymbolVector(x.base()); 970 } 971 auto GetSymbolVectorHelper::operator()(const CoarrayRef &x) const -> Result { 972 return x.base(); 973 } 974 975 const Symbol *GetLastTarget(const SymbolVector &symbols) { 976 auto end{std::crend(symbols)}; 977 // N.B. Neither clang nor g++ recognizes "symbols.crbegin()" here. 978 auto iter{std::find_if(std::crbegin(symbols), end, [](const Symbol &x) { 979 return x.attrs().HasAny( 980 {semantics::Attr::POINTER, semantics::Attr::TARGET}); 981 })}; 982 return iter == end ? nullptr : &**iter; 983 } 984 985 struct CollectSymbolsHelper 986 : public SetTraverse<CollectSymbolsHelper, semantics::UnorderedSymbolSet> { 987 using Base = SetTraverse<CollectSymbolsHelper, semantics::UnorderedSymbolSet>; 988 CollectSymbolsHelper() : Base{*this} {} 989 using Base::operator(); 990 semantics::UnorderedSymbolSet operator()(const Symbol &symbol) const { 991 return {symbol}; 992 } 993 }; 994 template <typename A> semantics::UnorderedSymbolSet CollectSymbols(const A &x) { 995 return CollectSymbolsHelper{}(x); 996 } 997 template semantics::UnorderedSymbolSet CollectSymbols(const Expr<SomeType> &); 998 template semantics::UnorderedSymbolSet CollectSymbols( 999 const Expr<SomeInteger> &); 1000 template semantics::UnorderedSymbolSet CollectSymbols( 1001 const Expr<SubscriptInteger> &); 1002 1003 struct CollectCudaSymbolsHelper : public SetTraverse<CollectCudaSymbolsHelper, 1004 semantics::UnorderedSymbolSet> { 1005 using Base = 1006 SetTraverse<CollectCudaSymbolsHelper, semantics::UnorderedSymbolSet>; 1007 CollectCudaSymbolsHelper() : Base{*this} {} 1008 using Base::operator(); 1009 semantics::UnorderedSymbolSet operator()(const Symbol &symbol) const { 1010 return {symbol}; 1011 } 1012 // Overload some of the operator() to filter out the symbols that are not 1013 // of interest for CUDA data transfer logic. 1014 semantics::UnorderedSymbolSet operator()(const DescriptorInquiry &) const { 1015 return {}; 1016 } 1017 semantics::UnorderedSymbolSet operator()(const Subscript &) const { 1018 return {}; 1019 } 1020 semantics::UnorderedSymbolSet operator()(const ProcedureRef &) const { 1021 return {}; 1022 } 1023 }; 1024 template <typename A> 1025 semantics::UnorderedSymbolSet CollectCudaSymbols(const A &x) { 1026 return CollectCudaSymbolsHelper{}(x); 1027 } 1028 template semantics::UnorderedSymbolSet CollectCudaSymbols( 1029 const Expr<SomeType> &); 1030 template semantics::UnorderedSymbolSet CollectCudaSymbols( 1031 const Expr<SomeInteger> &); 1032 template semantics::UnorderedSymbolSet CollectCudaSymbols( 1033 const Expr<SubscriptInteger> &); 1034 1035 // HasVectorSubscript() 1036 struct HasVectorSubscriptHelper 1037 : public AnyTraverse<HasVectorSubscriptHelper, bool, 1038 /*TraverseAssocEntityDetails=*/false> { 1039 using Base = AnyTraverse<HasVectorSubscriptHelper, bool, false>; 1040 HasVectorSubscriptHelper() : Base{*this} {} 1041 using Base::operator(); 1042 bool operator()(const Subscript &ss) const { 1043 return !std::holds_alternative<Triplet>(ss.u) && ss.Rank() > 0; 1044 } 1045 bool operator()(const ProcedureRef &) const { 1046 return false; // don't descend into function call arguments 1047 } 1048 }; 1049 1050 bool HasVectorSubscript(const Expr<SomeType> &expr) { 1051 return HasVectorSubscriptHelper{}(expr); 1052 } 1053 1054 // HasConstant() 1055 struct HasConstantHelper : public AnyTraverse<HasConstantHelper, bool, 1056 /*TraverseAssocEntityDetails=*/false> { 1057 using Base = AnyTraverse<HasConstantHelper, bool, false>; 1058 HasConstantHelper() : Base{*this} {} 1059 using Base::operator(); 1060 template <typename T> bool operator()(const Constant<T> &) const { 1061 return true; 1062 } 1063 // Only look for constant not in subscript. 1064 bool operator()(const Subscript &) const { return false; } 1065 }; 1066 1067 bool HasConstant(const Expr<SomeType> &expr) { 1068 return HasConstantHelper{}(expr); 1069 } 1070 1071 parser::Message *AttachDeclaration( 1072 parser::Message &message, const Symbol &symbol) { 1073 const Symbol *unhosted{&symbol}; 1074 while ( 1075 const auto *assoc{unhosted->detailsIf<semantics::HostAssocDetails>()}) { 1076 unhosted = &assoc->symbol(); 1077 } 1078 if (const auto *binding{ 1079 unhosted->detailsIf<semantics::ProcBindingDetails>()}) { 1080 if (binding->symbol().name() != symbol.name()) { 1081 message.Attach(binding->symbol().name(), 1082 "Procedure '%s' of type '%s' is bound to '%s'"_en_US, symbol.name(), 1083 symbol.owner().GetName().value(), binding->symbol().name()); 1084 return &message; 1085 } 1086 unhosted = &binding->symbol(); 1087 } 1088 if (const auto *use{symbol.detailsIf<semantics::UseDetails>()}) { 1089 message.Attach(use->location(), 1090 "'%s' is USE-associated with '%s' in module '%s'"_en_US, symbol.name(), 1091 unhosted->name(), GetUsedModule(*use).name()); 1092 } else { 1093 message.Attach( 1094 unhosted->name(), "Declaration of '%s'"_en_US, unhosted->name()); 1095 } 1096 return &message; 1097 } 1098 1099 parser::Message *AttachDeclaration( 1100 parser::Message *message, const Symbol &symbol) { 1101 return message ? AttachDeclaration(*message, symbol) : nullptr; 1102 } 1103 1104 class FindImpureCallHelper 1105 : public AnyTraverse<FindImpureCallHelper, std::optional<std::string>, 1106 /*TraverseAssocEntityDetails=*/false> { 1107 using Result = std::optional<std::string>; 1108 using Base = AnyTraverse<FindImpureCallHelper, Result, false>; 1109 1110 public: 1111 explicit FindImpureCallHelper(FoldingContext &c) : Base{*this}, context_{c} {} 1112 using Base::operator(); 1113 Result operator()(const ProcedureRef &call) const { 1114 if (auto chars{characteristics::Procedure::Characterize( 1115 call.proc(), context_, /*emitError=*/false)}) { 1116 if (chars->attrs.test(characteristics::Procedure::Attr::Pure)) { 1117 return (*this)(call.arguments()); 1118 } 1119 } 1120 return call.proc().GetName(); 1121 } 1122 1123 private: 1124 FoldingContext &context_; 1125 }; 1126 1127 std::optional<std::string> FindImpureCall( 1128 FoldingContext &context, const Expr<SomeType> &expr) { 1129 return FindImpureCallHelper{context}(expr); 1130 } 1131 std::optional<std::string> FindImpureCall( 1132 FoldingContext &context, const ProcedureRef &proc) { 1133 return FindImpureCallHelper{context}(proc); 1134 } 1135 1136 // Common handling for procedure pointer compatibility of left- and right-hand 1137 // sides. Returns nullopt if they're compatible. Otherwise, it returns a 1138 // message that needs to be augmented by the names of the left and right sides 1139 // and the content of the "whyNotCompatible" string. 1140 std::optional<parser::MessageFixedText> CheckProcCompatibility(bool isCall, 1141 const std::optional<characteristics::Procedure> &lhsProcedure, 1142 const characteristics::Procedure *rhsProcedure, 1143 const SpecificIntrinsic *specificIntrinsic, std::string &whyNotCompatible, 1144 std::optional<std::string> &warning, bool ignoreImplicitVsExplicit) { 1145 std::optional<parser::MessageFixedText> msg; 1146 if (!lhsProcedure) { 1147 msg = "In assignment to object %s, the target '%s' is a procedure" 1148 " designator"_err_en_US; 1149 } else if (!rhsProcedure) { 1150 msg = "In assignment to procedure %s, the characteristics of the target" 1151 " procedure '%s' could not be determined"_err_en_US; 1152 } else if (!isCall && lhsProcedure->functionResult && 1153 rhsProcedure->functionResult && 1154 !lhsProcedure->functionResult->IsCompatibleWith( 1155 *rhsProcedure->functionResult, &whyNotCompatible)) { 1156 msg = 1157 "Function %s associated with incompatible function designator '%s': %s"_err_en_US; 1158 } else if (lhsProcedure->IsCompatibleWith(*rhsProcedure, 1159 ignoreImplicitVsExplicit, &whyNotCompatible, specificIntrinsic, 1160 &warning)) { 1161 // OK 1162 } else if (isCall) { 1163 msg = "Procedure %s associated with result of reference to function '%s'" 1164 " that is an incompatible procedure pointer: %s"_err_en_US; 1165 } else if (lhsProcedure->IsPure() && !rhsProcedure->IsPure()) { 1166 msg = "PURE procedure %s may not be associated with non-PURE" 1167 " procedure designator '%s'"_err_en_US; 1168 } else if (lhsProcedure->IsFunction() && rhsProcedure->IsSubroutine()) { 1169 msg = "Function %s may not be associated with subroutine" 1170 " designator '%s'"_err_en_US; 1171 } else if (lhsProcedure->IsSubroutine() && rhsProcedure->IsFunction()) { 1172 msg = "Subroutine %s may not be associated with function" 1173 " designator '%s'"_err_en_US; 1174 } else if (lhsProcedure->HasExplicitInterface() && 1175 !rhsProcedure->HasExplicitInterface()) { 1176 // Section 10.2.2.4, paragraph 3 prohibits associating a procedure pointer 1177 // that has an explicit interface with a procedure whose characteristics 1178 // don't match. That's the case if the target procedure has an implicit 1179 // interface. But this case is allowed by several other compilers as long 1180 // as the explicit interface can be called via an implicit interface. 1181 if (!lhsProcedure->CanBeCalledViaImplicitInterface()) { 1182 msg = "Procedure %s with explicit interface that cannot be called via " 1183 "an implicit interface cannot be associated with procedure " 1184 "designator with an implicit interface"_err_en_US; 1185 } 1186 } else if (!lhsProcedure->HasExplicitInterface() && 1187 rhsProcedure->HasExplicitInterface()) { 1188 // OK if the target can be called via an implicit interface 1189 if (!rhsProcedure->CanBeCalledViaImplicitInterface() && 1190 !specificIntrinsic) { 1191 msg = "Procedure %s with implicit interface may not be associated " 1192 "with procedure designator '%s' with explicit interface that " 1193 "cannot be called via an implicit interface"_err_en_US; 1194 } 1195 } else { 1196 msg = "Procedure %s associated with incompatible procedure" 1197 " designator '%s': %s"_err_en_US; 1198 } 1199 return msg; 1200 } 1201 1202 // GetLastPointerSymbol() 1203 static const Symbol *GetLastPointerSymbol(const Symbol &symbol) { 1204 return IsPointer(GetAssociationRoot(symbol)) ? &symbol : nullptr; 1205 } 1206 static const Symbol *GetLastPointerSymbol(const SymbolRef &symbol) { 1207 return GetLastPointerSymbol(*symbol); 1208 } 1209 static const Symbol *GetLastPointerSymbol(const Component &x) { 1210 const Symbol &c{x.GetLastSymbol()}; 1211 return IsPointer(c) ? &c : GetLastPointerSymbol(x.base()); 1212 } 1213 static const Symbol *GetLastPointerSymbol(const NamedEntity &x) { 1214 const auto *c{x.UnwrapComponent()}; 1215 return c ? GetLastPointerSymbol(*c) : GetLastPointerSymbol(x.GetLastSymbol()); 1216 } 1217 static const Symbol *GetLastPointerSymbol(const ArrayRef &x) { 1218 return GetLastPointerSymbol(x.base()); 1219 } 1220 static const Symbol *GetLastPointerSymbol(const CoarrayRef &x) { 1221 return nullptr; 1222 } 1223 const Symbol *GetLastPointerSymbol(const DataRef &x) { 1224 return common::visit( 1225 [](const auto &y) { return GetLastPointerSymbol(y); }, x.u); 1226 } 1227 1228 template <TypeCategory TO, TypeCategory FROM> 1229 static std::optional<Expr<SomeType>> DataConstantConversionHelper( 1230 FoldingContext &context, const DynamicType &toType, 1231 const Expr<SomeType> &expr) { 1232 DynamicType sizedType{FROM, toType.kind()}; 1233 if (auto sized{ 1234 Fold(context, ConvertToType(sizedType, Expr<SomeType>{expr}))}) { 1235 if (const auto *someExpr{UnwrapExpr<Expr<SomeKind<FROM>>>(*sized)}) { 1236 return common::visit( 1237 [](const auto &w) -> std::optional<Expr<SomeType>> { 1238 using FromType = ResultType<decltype(w)>; 1239 static constexpr int kind{FromType::kind}; 1240 if constexpr (IsValidKindOfIntrinsicType(TO, kind)) { 1241 if (const auto *fromConst{UnwrapExpr<Constant<FromType>>(w)}) { 1242 using FromWordType = typename FromType::Scalar; 1243 using LogicalType = value::Logical<FromWordType::bits>; 1244 using ElementType = 1245 std::conditional_t<TO == TypeCategory::Logical, LogicalType, 1246 typename LogicalType::Word>; 1247 std::vector<ElementType> values; 1248 auto at{fromConst->lbounds()}; 1249 auto shape{fromConst->shape()}; 1250 for (auto n{GetSize(shape)}; n-- > 0; 1251 fromConst->IncrementSubscripts(at)) { 1252 auto elt{fromConst->At(at)}; 1253 if constexpr (TO == TypeCategory::Logical) { 1254 values.emplace_back(std::move(elt)); 1255 } else { 1256 values.emplace_back(elt.word()); 1257 } 1258 } 1259 return {AsGenericExpr(AsExpr(Constant<Type<TO, kind>>{ 1260 std::move(values), std::move(shape)}))}; 1261 } 1262 } 1263 return std::nullopt; 1264 }, 1265 someExpr->u); 1266 } 1267 } 1268 return std::nullopt; 1269 } 1270 1271 std::optional<Expr<SomeType>> DataConstantConversionExtension( 1272 FoldingContext &context, const DynamicType &toType, 1273 const Expr<SomeType> &expr0) { 1274 Expr<SomeType> expr{Fold(context, Expr<SomeType>{expr0})}; 1275 if (!IsActuallyConstant(expr)) { 1276 return std::nullopt; 1277 } 1278 if (auto fromType{expr.GetType()}) { 1279 if (toType.category() == TypeCategory::Logical && 1280 fromType->category() == TypeCategory::Integer) { 1281 return DataConstantConversionHelper<TypeCategory::Logical, 1282 TypeCategory::Integer>(context, toType, expr); 1283 } 1284 if (toType.category() == TypeCategory::Integer && 1285 fromType->category() == TypeCategory::Logical) { 1286 return DataConstantConversionHelper<TypeCategory::Integer, 1287 TypeCategory::Logical>(context, toType, expr); 1288 } 1289 } 1290 return std::nullopt; 1291 } 1292 1293 bool IsAllocatableOrPointerObject(const Expr<SomeType> &expr) { 1294 const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)}; 1295 return (sym && 1296 semantics::IsAllocatableOrObjectPointer(&sym->GetUltimate())) || 1297 evaluate::IsObjectPointer(expr); 1298 } 1299 1300 bool IsAllocatableDesignator(const Expr<SomeType> &expr) { 1301 // Allocatable sub-objects are not themselves allocatable (9.5.3.1 NOTE 2). 1302 if (const semantics::Symbol * 1303 sym{UnwrapWholeSymbolOrComponentOrCoarrayRef(expr)}) { 1304 return semantics::IsAllocatable(sym->GetUltimate()); 1305 } 1306 return false; 1307 } 1308 1309 bool MayBePassedAsAbsentOptional(const Expr<SomeType> &expr) { 1310 const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)}; 1311 // 15.5.2.12 1. is pretty clear that an unallocated allocatable/pointer actual 1312 // may be passed to a non-allocatable/non-pointer optional dummy. Note that 1313 // other compilers (like nag, nvfortran, ifort, gfortran and xlf) seems to 1314 // ignore this point in intrinsic contexts (e.g CMPLX argument). 1315 return (sym && semantics::IsOptional(*sym)) || 1316 IsAllocatableOrPointerObject(expr); 1317 } 1318 1319 std::optional<Expr<SomeType>> HollerithToBOZ(FoldingContext &context, 1320 const Expr<SomeType> &expr, const DynamicType &type) { 1321 if (std::optional<std::string> chValue{GetScalarConstantValue<Ascii>(expr)}) { 1322 // Pad on the right with spaces when short, truncate the right if long. 1323 auto bytes{static_cast<std::size_t>( 1324 ToInt64(type.MeasureSizeInBytes(context, false)).value())}; 1325 BOZLiteralConstant bits{0}; 1326 for (std::size_t j{0}; j < bytes; ++j) { 1327 auto idx{isHostLittleEndian ? j : bytes - j - 1}; 1328 char ch{idx >= chValue->size() ? ' ' : chValue->at(idx)}; 1329 BOZLiteralConstant chBOZ{static_cast<unsigned char>(ch)}; 1330 bits = bits.IOR(chBOZ.SHIFTL(8 * j)); 1331 } 1332 return ConvertToType(type, Expr<SomeType>{bits}); 1333 } else { 1334 return std::nullopt; 1335 } 1336 } 1337 1338 // Extracts a whole symbol being used as a bound of a dummy argument, 1339 // possibly wrapped with parentheses or MAX(0, ...). 1340 // Works with any integer expression. 1341 template <typename T> const Symbol *GetBoundSymbol(const Expr<T> &); 1342 template <int KIND> 1343 const Symbol *GetBoundSymbol( 1344 const Expr<Type<TypeCategory::Integer, KIND>> &expr) { 1345 using T = Type<TypeCategory::Integer, KIND>; 1346 return common::visit( 1347 common::visitors{ 1348 [](const Extremum<T> &max) -> const Symbol * { 1349 if (max.ordering == Ordering::Greater) { 1350 if (auto zero{ToInt64(max.left())}; zero && *zero == 0) { 1351 return GetBoundSymbol(max.right()); 1352 } 1353 } 1354 return nullptr; 1355 }, 1356 [](const Parentheses<T> &x) { return GetBoundSymbol(x.left()); }, 1357 [](const Designator<T> &x) -> const Symbol * { 1358 if (const auto *ref{std::get_if<SymbolRef>(&x.u)}) { 1359 return &**ref; 1360 } 1361 return nullptr; 1362 }, 1363 [](const Convert<T, TypeCategory::Integer> &x) { 1364 return common::visit( 1365 [](const auto &y) -> const Symbol * { 1366 using yType = std::decay_t<decltype(y)>; 1367 using yResult = typename yType::Result; 1368 if constexpr (yResult::kind <= KIND) { 1369 return GetBoundSymbol(y); 1370 } else { 1371 return nullptr; 1372 } 1373 }, 1374 x.left().u); 1375 }, 1376 [](const auto &) -> const Symbol * { return nullptr; }, 1377 }, 1378 expr.u); 1379 } 1380 template <> 1381 const Symbol *GetBoundSymbol<SomeInteger>(const Expr<SomeInteger> &expr) { 1382 return common::visit( 1383 [](const auto &kindExpr) { return GetBoundSymbol(kindExpr); }, expr.u); 1384 } 1385 1386 template <typename T> 1387 std::optional<bool> AreEquivalentInInterface( 1388 const Expr<T> &x, const Expr<T> &y) { 1389 auto xVal{ToInt64(x)}; 1390 auto yVal{ToInt64(y)}; 1391 if (xVal && yVal) { 1392 return *xVal == *yVal; 1393 } else if (xVal || yVal) { 1394 return false; 1395 } 1396 const Symbol *xSym{GetBoundSymbol(x)}; 1397 const Symbol *ySym{GetBoundSymbol(y)}; 1398 if (xSym && ySym) { 1399 if (&xSym->GetUltimate() == &ySym->GetUltimate()) { 1400 return true; // USE/host associated same symbol 1401 } 1402 auto xNum{semantics::GetDummyArgumentNumber(xSym)}; 1403 auto yNum{semantics::GetDummyArgumentNumber(ySym)}; 1404 if (xNum && yNum) { 1405 if (*xNum == *yNum) { 1406 auto xType{DynamicType::From(*xSym)}; 1407 auto yType{DynamicType::From(*ySym)}; 1408 return xType && yType && xType->IsEquivalentTo(*yType); 1409 } 1410 } 1411 return false; 1412 } else if (xSym || ySym) { 1413 return false; 1414 } 1415 // Neither expression is an integer constant or a whole symbol. 1416 if (x == y) { 1417 return true; 1418 } else { 1419 return std::nullopt; // not sure 1420 } 1421 } 1422 template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>( 1423 const Expr<SubscriptInteger> &, const Expr<SubscriptInteger> &); 1424 template std::optional<bool> AreEquivalentInInterface<SomeInteger>( 1425 const Expr<SomeInteger> &, const Expr<SomeInteger> &); 1426 1427 bool CheckForCoindexedObject(parser::ContextualMessages &messages, 1428 const std::optional<ActualArgument> &arg, const std::string &procName, 1429 const std::string &argName) { 1430 if (arg && ExtractCoarrayRef(arg->UnwrapExpr())) { 1431 messages.Say(arg->sourceLocation(), 1432 "'%s' argument to '%s' may not be a coindexed object"_err_en_US, 1433 argName, procName); 1434 return false; 1435 } else { 1436 return true; 1437 } 1438 } 1439 1440 } // namespace Fortran::evaluate 1441 1442 namespace Fortran::semantics { 1443 1444 const Symbol &ResolveAssociations(const Symbol &original) { 1445 const Symbol &symbol{original.GetUltimate()}; 1446 if (const auto *details{symbol.detailsIf<AssocEntityDetails>()}) { 1447 if (!details->rank()) { // Not RANK(n) or RANK(*) 1448 if (const Symbol * nested{UnwrapWholeSymbolDataRef(details->expr())}) { 1449 return ResolveAssociations(*nested); 1450 } 1451 } 1452 } 1453 return symbol; 1454 } 1455 1456 // When a construct association maps to a variable, and that variable 1457 // is not an array with a vector-valued subscript, return the base 1458 // Symbol of that variable, else nullptr. Descends into other construct 1459 // associations when one associations maps to another. 1460 static const Symbol *GetAssociatedVariable(const AssocEntityDetails &details) { 1461 if (const auto &expr{details.expr()}) { 1462 if (IsVariable(*expr) && !HasVectorSubscript(*expr)) { 1463 if (const Symbol * varSymbol{GetFirstSymbol(*expr)}) { 1464 return &GetAssociationRoot(*varSymbol); 1465 } 1466 } 1467 } 1468 return nullptr; 1469 } 1470 1471 const Symbol &GetAssociationRoot(const Symbol &original) { 1472 const Symbol &symbol{ResolveAssociations(original)}; 1473 if (const auto *details{symbol.detailsIf<AssocEntityDetails>()}) { 1474 if (const Symbol * root{GetAssociatedVariable(*details)}) { 1475 return *root; 1476 } 1477 } 1478 return symbol; 1479 } 1480 1481 const Symbol *GetMainEntry(const Symbol *symbol) { 1482 if (symbol) { 1483 if (const auto *subpDetails{symbol->detailsIf<SubprogramDetails>()}) { 1484 if (const Scope * scope{subpDetails->entryScope()}) { 1485 if (const Symbol * main{scope->symbol()}) { 1486 return main; 1487 } 1488 } 1489 } 1490 } 1491 return symbol; 1492 } 1493 1494 bool IsVariableName(const Symbol &original) { 1495 const Symbol &ultimate{original.GetUltimate()}; 1496 return !IsNamedConstant(ultimate) && 1497 (ultimate.has<ObjectEntityDetails>() || 1498 ultimate.has<AssocEntityDetails>()); 1499 } 1500 1501 static bool IsPureProcedureImpl( 1502 const Symbol &original, semantics::UnorderedSymbolSet &set) { 1503 // An ENTRY is pure if its containing subprogram is 1504 const Symbol &symbol{DEREF(GetMainEntry(&original.GetUltimate()))}; 1505 if (set.find(symbol) != set.end()) { 1506 return true; 1507 } 1508 set.emplace(symbol); 1509 if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) { 1510 if (procDetails->procInterface()) { 1511 // procedure with a pure interface 1512 return IsPureProcedureImpl(*procDetails->procInterface(), set); 1513 } 1514 } else if (const auto *details{symbol.detailsIf<ProcBindingDetails>()}) { 1515 return IsPureProcedureImpl(details->symbol(), set); 1516 } else if (!IsProcedure(symbol)) { 1517 return false; 1518 } 1519 if (IsStmtFunction(symbol)) { 1520 // Section 15.7(1) states that a statement function is PURE if it does not 1521 // reference an IMPURE procedure or a VOLATILE variable 1522 if (const auto &expr{symbol.get<SubprogramDetails>().stmtFunction()}) { 1523 for (const SymbolRef &ref : evaluate::CollectSymbols(*expr)) { 1524 if (&*ref == &symbol) { 1525 return false; // error recovery, recursion is caught elsewhere 1526 } 1527 if (IsFunction(*ref) && !IsPureProcedureImpl(*ref, set)) { 1528 return false; 1529 } 1530 if (ref->GetUltimate().attrs().test(Attr::VOLATILE)) { 1531 return false; 1532 } 1533 } 1534 } 1535 return true; // statement function was not found to be impure 1536 } 1537 return symbol.attrs().test(Attr::PURE) || 1538 (symbol.attrs().test(Attr::ELEMENTAL) && 1539 !symbol.attrs().test(Attr::IMPURE)); 1540 } 1541 1542 bool IsPureProcedure(const Symbol &original) { 1543 semantics::UnorderedSymbolSet set; 1544 return IsPureProcedureImpl(original, set); 1545 } 1546 1547 bool IsPureProcedure(const Scope &scope) { 1548 const Symbol *symbol{scope.GetSymbol()}; 1549 return symbol && IsPureProcedure(*symbol); 1550 } 1551 1552 bool IsExplicitlyImpureProcedure(const Symbol &original) { 1553 // An ENTRY is IMPURE if its containing subprogram is so 1554 return DEREF(GetMainEntry(&original.GetUltimate())) 1555 .attrs() 1556 .test(Attr::IMPURE); 1557 } 1558 1559 bool IsElementalProcedure(const Symbol &original) { 1560 // An ENTRY is elemental if its containing subprogram is 1561 const Symbol &symbol{DEREF(GetMainEntry(&original.GetUltimate()))}; 1562 if (IsProcedure(symbol)) { 1563 auto &foldingContext{symbol.owner().context().foldingContext()}; 1564 auto restorer{foldingContext.messages().DiscardMessages()}; 1565 auto proc{evaluate::characteristics::Procedure::Characterize( 1566 symbol, foldingContext)}; 1567 return proc && 1568 proc->attrs.test(evaluate::characteristics::Procedure::Attr::Elemental); 1569 } else { 1570 return false; 1571 } 1572 } 1573 1574 bool IsFunction(const Symbol &symbol) { 1575 const Symbol &ultimate{symbol.GetUltimate()}; 1576 return ultimate.test(Symbol::Flag::Function) || 1577 (!ultimate.test(Symbol::Flag::Subroutine) && 1578 common::visit( 1579 common::visitors{ 1580 [](const SubprogramDetails &x) { return x.isFunction(); }, 1581 [](const ProcEntityDetails &x) { 1582 const Symbol *ifc{x.procInterface()}; 1583 return x.type() || (ifc && IsFunction(*ifc)); 1584 }, 1585 [](const ProcBindingDetails &x) { 1586 return IsFunction(x.symbol()); 1587 }, 1588 [](const auto &) { return false; }, 1589 }, 1590 ultimate.details())); 1591 } 1592 1593 bool IsFunction(const Scope &scope) { 1594 const Symbol *symbol{scope.GetSymbol()}; 1595 return symbol && IsFunction(*symbol); 1596 } 1597 1598 bool IsProcedure(const Symbol &symbol) { 1599 return common::visit(common::visitors{ 1600 [&symbol](const SubprogramDetails &) { 1601 const Scope *scope{symbol.scope()}; 1602 // Main programs & BLOCK DATA are not procedures. 1603 return !scope || 1604 scope->kind() == Scope::Kind::Subprogram; 1605 }, 1606 [](const SubprogramNameDetails &) { return true; }, 1607 [](const ProcEntityDetails &) { return true; }, 1608 [](const GenericDetails &) { return true; }, 1609 [](const ProcBindingDetails &) { return true; }, 1610 [](const auto &) { return false; }, 1611 }, 1612 symbol.GetUltimate().details()); 1613 } 1614 1615 bool IsProcedure(const Scope &scope) { 1616 const Symbol *symbol{scope.GetSymbol()}; 1617 return symbol && IsProcedure(*symbol); 1618 } 1619 1620 bool IsProcedurePointer(const Symbol &original) { 1621 const Symbol &symbol{GetAssociationRoot(original)}; 1622 return IsPointer(symbol) && IsProcedure(symbol); 1623 } 1624 1625 bool IsProcedurePointer(const Symbol *symbol) { 1626 return symbol && IsProcedurePointer(*symbol); 1627 } 1628 1629 bool IsObjectPointer(const Symbol *original) { 1630 if (original) { 1631 const Symbol &symbol{GetAssociationRoot(*original)}; 1632 return IsPointer(symbol) && !IsProcedure(symbol); 1633 } else { 1634 return false; 1635 } 1636 } 1637 1638 bool IsAllocatableOrObjectPointer(const Symbol *original) { 1639 if (original) { 1640 const Symbol &ultimate{original->GetUltimate()}; 1641 if (const auto *assoc{ultimate.detailsIf<AssocEntityDetails>()}) { 1642 // Only SELECT RANK construct entities can be ALLOCATABLE/POINTER. 1643 return (assoc->rank() || assoc->IsAssumedSize() || 1644 assoc->IsAssumedRank()) && 1645 IsAllocatableOrObjectPointer(UnwrapWholeSymbolDataRef(assoc->expr())); 1646 } else { 1647 return IsAllocatable(ultimate) || 1648 (IsPointer(ultimate) && !IsProcedure(ultimate)); 1649 } 1650 } else { 1651 return false; 1652 } 1653 } 1654 1655 const Symbol *FindCommonBlockContaining(const Symbol &original) { 1656 const Symbol &root{GetAssociationRoot(original)}; 1657 const auto *details{root.detailsIf<ObjectEntityDetails>()}; 1658 return details ? details->commonBlock() : nullptr; 1659 } 1660 1661 // 3.11 automatic data object 1662 bool IsAutomatic(const Symbol &original) { 1663 const Symbol &symbol{original.GetUltimate()}; 1664 if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 1665 if (!object->isDummy() && !IsAllocatable(symbol) && !IsPointer(symbol)) { 1666 if (const DeclTypeSpec * type{symbol.GetType()}) { 1667 // If a type parameter value is not a constant expression, the 1668 // object is automatic. 1669 if (type->category() == DeclTypeSpec::Character) { 1670 if (const auto &length{ 1671 type->characterTypeSpec().length().GetExplicit()}) { 1672 if (!evaluate::IsConstantExpr(*length)) { 1673 return true; 1674 } 1675 } 1676 } else if (const DerivedTypeSpec * derived{type->AsDerived()}) { 1677 for (const auto &pair : derived->parameters()) { 1678 if (const auto &value{pair.second.GetExplicit()}) { 1679 if (!evaluate::IsConstantExpr(*value)) { 1680 return true; 1681 } 1682 } 1683 } 1684 } 1685 } 1686 // If an array bound is not a constant expression, the object is 1687 // automatic. 1688 for (const ShapeSpec &dim : object->shape()) { 1689 if (const auto &lb{dim.lbound().GetExplicit()}) { 1690 if (!evaluate::IsConstantExpr(*lb)) { 1691 return true; 1692 } 1693 } 1694 if (const auto &ub{dim.ubound().GetExplicit()}) { 1695 if (!evaluate::IsConstantExpr(*ub)) { 1696 return true; 1697 } 1698 } 1699 } 1700 } 1701 } 1702 return false; 1703 } 1704 1705 bool IsSaved(const Symbol &original) { 1706 const Symbol &symbol{GetAssociationRoot(original)}; 1707 const Scope &scope{symbol.owner()}; 1708 const common::LanguageFeatureControl &features{ 1709 scope.context().languageFeatures()}; 1710 auto scopeKind{scope.kind()}; 1711 if (symbol.has<AssocEntityDetails>()) { 1712 return false; // ASSOCIATE(non-variable) 1713 } else if (scopeKind == Scope::Kind::DerivedType) { 1714 return false; // this is a component 1715 } else if (symbol.attrs().test(Attr::SAVE)) { 1716 return true; // explicit SAVE attribute 1717 } else if (IsDummy(symbol) || IsFunctionResult(symbol) || 1718 IsAutomatic(symbol) || IsNamedConstant(symbol)) { 1719 return false; 1720 } else if (scopeKind == Scope::Kind::Module || 1721 (scopeKind == Scope::Kind::MainProgram && 1722 (symbol.attrs().test(Attr::TARGET) || evaluate::IsCoarray(symbol)) && 1723 Fortran::evaluate::CanCUDASymbolHaveSaveAttr(symbol))) { 1724 // 8.5.16p4 1725 // In main programs, implied SAVE matters only for pointer 1726 // initialization targets and coarrays. 1727 return true; 1728 } else if (scopeKind == Scope::Kind::MainProgram && 1729 (features.IsEnabled(common::LanguageFeature::SaveMainProgram) || 1730 (features.IsEnabled( 1731 common::LanguageFeature::SaveBigMainProgramVariables) && 1732 symbol.size() > 32)) && 1733 Fortran::evaluate::CanCUDASymbolHaveSaveAttr(symbol)) { 1734 // With SaveBigMainProgramVariables, keeping all unsaved main program 1735 // variables of 32 bytes or less on the stack allows keeping numerical and 1736 // logical scalars, small scalar characters or derived, small arrays, and 1737 // scalar descriptors on the stack. This leaves more room for lower level 1738 // optimizers to do register promotion or get easy aliasing information. 1739 return true; 1740 } else if (features.IsEnabled(common::LanguageFeature::DefaultSave) && 1741 (scopeKind == Scope::Kind::MainProgram || 1742 (scope.kind() == Scope::Kind::Subprogram && 1743 !(scope.symbol() && 1744 scope.symbol()->attrs().test(Attr::RECURSIVE))))) { 1745 // -fno-automatic/-save/-Msave option applies to all objects in executable 1746 // main programs and subprograms unless they are explicitly RECURSIVE. 1747 return true; 1748 } else if (symbol.test(Symbol::Flag::InDataStmt)) { 1749 return true; 1750 } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}; 1751 object && object->init()) { 1752 return true; 1753 } else if (IsProcedurePointer(symbol) && symbol.has<ProcEntityDetails>() && 1754 symbol.get<ProcEntityDetails>().init()) { 1755 return true; 1756 } else if (scope.hasSAVE()) { 1757 return true; // bare SAVE statement 1758 } else if (const Symbol * block{FindCommonBlockContaining(symbol)}; 1759 block && block->attrs().test(Attr::SAVE)) { 1760 return true; // in COMMON with SAVE 1761 } else { 1762 return false; 1763 } 1764 } 1765 1766 bool IsDummy(const Symbol &symbol) { 1767 return common::visit( 1768 common::visitors{[](const EntityDetails &x) { return x.isDummy(); }, 1769 [](const ObjectEntityDetails &x) { return x.isDummy(); }, 1770 [](const ProcEntityDetails &x) { return x.isDummy(); }, 1771 [](const SubprogramDetails &x) { return x.isDummy(); }, 1772 [](const auto &) { return false; }}, 1773 ResolveAssociations(symbol).details()); 1774 } 1775 1776 bool IsAssumedShape(const Symbol &symbol) { 1777 const Symbol &ultimate{ResolveAssociations(symbol)}; 1778 const auto *object{ultimate.detailsIf<ObjectEntityDetails>()}; 1779 return object && object->IsAssumedShape() && 1780 !semantics::IsAllocatableOrObjectPointer(&ultimate); 1781 } 1782 1783 bool IsDeferredShape(const Symbol &symbol) { 1784 const Symbol &ultimate{ResolveAssociations(symbol)}; 1785 const auto *object{ultimate.detailsIf<ObjectEntityDetails>()}; 1786 return object && object->CanBeDeferredShape() && 1787 semantics::IsAllocatableOrObjectPointer(&ultimate); 1788 } 1789 1790 bool IsFunctionResult(const Symbol &original) { 1791 const Symbol &symbol{GetAssociationRoot(original)}; 1792 return common::visit( 1793 common::visitors{ 1794 [](const EntityDetails &x) { return x.isFuncResult(); }, 1795 [](const ObjectEntityDetails &x) { return x.isFuncResult(); }, 1796 [](const ProcEntityDetails &x) { return x.isFuncResult(); }, 1797 [](const auto &) { return false; }, 1798 }, 1799 symbol.details()); 1800 } 1801 1802 bool IsKindTypeParameter(const Symbol &symbol) { 1803 const auto *param{symbol.GetUltimate().detailsIf<TypeParamDetails>()}; 1804 return param && param->attr() == common::TypeParamAttr::Kind; 1805 } 1806 1807 bool IsLenTypeParameter(const Symbol &symbol) { 1808 const auto *param{symbol.GetUltimate().detailsIf<TypeParamDetails>()}; 1809 return param && param->attr() == common::TypeParamAttr::Len; 1810 } 1811 1812 bool IsExtensibleType(const DerivedTypeSpec *derived) { 1813 return !IsSequenceOrBindCType(derived) && !IsIsoCType(derived); 1814 } 1815 1816 bool IsSequenceOrBindCType(const DerivedTypeSpec *derived) { 1817 return derived && 1818 (derived->typeSymbol().attrs().test(Attr::BIND_C) || 1819 derived->typeSymbol().get<DerivedTypeDetails>().sequence()); 1820 } 1821 1822 static bool IsSameModule(const Scope *x, const Scope *y) { 1823 if (x == y) { 1824 return true; 1825 } else if (x && y) { 1826 // Allow for a builtin module to be read from distinct paths 1827 const Symbol *xSym{x->symbol()}; 1828 const Symbol *ySym{y->symbol()}; 1829 if (xSym && ySym && xSym->name() == ySym->name()) { 1830 const auto *xMod{xSym->detailsIf<ModuleDetails>()}; 1831 const auto *yMod{ySym->detailsIf<ModuleDetails>()}; 1832 if (xMod && yMod) { 1833 auto xHash{xMod->moduleFileHash()}; 1834 auto yHash{yMod->moduleFileHash()}; 1835 return xHash && yHash && *xHash == *yHash; 1836 } 1837 } 1838 } 1839 return false; 1840 } 1841 1842 bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name) { 1843 if (derived) { 1844 const auto &symbol{derived->typeSymbol()}; 1845 const Scope &scope{symbol.owner()}; 1846 return symbol.name() == "__builtin_"s + name && 1847 IsSameModule(&scope, scope.context().GetBuiltinsScope()); 1848 } else { 1849 return false; 1850 } 1851 } 1852 1853 bool IsBuiltinCPtr(const Symbol &symbol) { 1854 if (const DeclTypeSpec *declType = symbol.GetType()) { 1855 if (const DerivedTypeSpec *derived = declType->AsDerived()) { 1856 return IsIsoCType(derived); 1857 } 1858 } 1859 return false; 1860 } 1861 1862 bool IsIsoCType(const DerivedTypeSpec *derived) { 1863 return IsBuiltinDerivedType(derived, "c_ptr") || 1864 IsBuiltinDerivedType(derived, "c_funptr"); 1865 } 1866 1867 bool IsEventType(const DerivedTypeSpec *derived) { 1868 return IsBuiltinDerivedType(derived, "event_type"); 1869 } 1870 1871 bool IsLockType(const DerivedTypeSpec *derived) { 1872 return IsBuiltinDerivedType(derived, "lock_type"); 1873 } 1874 1875 bool IsNotifyType(const DerivedTypeSpec *derived) { 1876 return IsBuiltinDerivedType(derived, "notify_type"); 1877 } 1878 1879 bool IsIeeeFlagType(const DerivedTypeSpec *derived) { 1880 return IsBuiltinDerivedType(derived, "ieee_flag_type"); 1881 } 1882 1883 bool IsIeeeRoundType(const DerivedTypeSpec *derived) { 1884 return IsBuiltinDerivedType(derived, "ieee_round_type"); 1885 } 1886 1887 bool IsTeamType(const DerivedTypeSpec *derived) { 1888 return IsBuiltinDerivedType(derived, "team_type"); 1889 } 1890 1891 bool IsBadCoarrayType(const DerivedTypeSpec *derived) { 1892 return IsTeamType(derived) || IsIsoCType(derived); 1893 } 1894 1895 bool IsEventTypeOrLockType(const DerivedTypeSpec *derivedTypeSpec) { 1896 return IsEventType(derivedTypeSpec) || IsLockType(derivedTypeSpec); 1897 } 1898 1899 int CountLenParameters(const DerivedTypeSpec &type) { 1900 return llvm::count_if( 1901 type.parameters(), [](const auto &pair) { return pair.second.isLen(); }); 1902 } 1903 1904 int CountNonConstantLenParameters(const DerivedTypeSpec &type) { 1905 return llvm::count_if(type.parameters(), [](const auto &pair) { 1906 if (!pair.second.isLen()) { 1907 return false; 1908 } else if (const auto &expr{pair.second.GetExplicit()}) { 1909 return !IsConstantExpr(*expr); 1910 } else { 1911 return true; 1912 } 1913 }); 1914 } 1915 1916 const Symbol &GetUsedModule(const UseDetails &details) { 1917 return DEREF(details.symbol().owner().symbol()); 1918 } 1919 1920 static const Symbol *FindFunctionResult( 1921 const Symbol &original, UnorderedSymbolSet &seen) { 1922 const Symbol &root{GetAssociationRoot(original)}; 1923 ; 1924 if (!seen.insert(root).second) { 1925 return nullptr; // don't loop 1926 } 1927 return common::visit( 1928 common::visitors{[](const SubprogramDetails &subp) { 1929 return subp.isFunction() ? &subp.result() : nullptr; 1930 }, 1931 [&](const ProcEntityDetails &proc) { 1932 const Symbol *iface{proc.procInterface()}; 1933 return iface ? FindFunctionResult(*iface, seen) : nullptr; 1934 }, 1935 [&](const ProcBindingDetails &binding) { 1936 return FindFunctionResult(binding.symbol(), seen); 1937 }, 1938 [](const auto &) -> const Symbol * { return nullptr; }}, 1939 root.details()); 1940 } 1941 1942 const Symbol *FindFunctionResult(const Symbol &symbol) { 1943 UnorderedSymbolSet seen; 1944 return FindFunctionResult(symbol, seen); 1945 } 1946 1947 // These are here in Evaluate/tools.cpp so that Evaluate can use 1948 // them; they cannot be defined in symbol.h due to the dependence 1949 // on Scope. 1950 1951 bool SymbolSourcePositionCompare::operator()( 1952 const SymbolRef &x, const SymbolRef &y) const { 1953 return x->GetSemanticsContext().allCookedSources().Precedes( 1954 x->name(), y->name()); 1955 } 1956 bool SymbolSourcePositionCompare::operator()( 1957 const MutableSymbolRef &x, const MutableSymbolRef &y) const { 1958 return x->GetSemanticsContext().allCookedSources().Precedes( 1959 x->name(), y->name()); 1960 } 1961 1962 SemanticsContext &Symbol::GetSemanticsContext() const { 1963 return DEREF(owner_).context(); 1964 } 1965 1966 bool AreTkCompatibleTypes(const DeclTypeSpec *x, const DeclTypeSpec *y) { 1967 if (x && y) { 1968 if (auto xDt{evaluate::DynamicType::From(*x)}) { 1969 if (auto yDt{evaluate::DynamicType::From(*y)}) { 1970 return xDt->IsTkCompatibleWith(*yDt); 1971 } 1972 } 1973 } 1974 return false; 1975 } 1976 1977 common::IgnoreTKRSet GetIgnoreTKR(const Symbol &symbol) { 1978 common::IgnoreTKRSet result; 1979 if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { 1980 result = object->ignoreTKR(); 1981 if (const Symbol * ownerSymbol{symbol.owner().symbol()}) { 1982 if (const auto *ownerSubp{ownerSymbol->detailsIf<SubprogramDetails>()}) { 1983 if (ownerSubp->defaultIgnoreTKR()) { 1984 result |= common::ignoreTKRAll; 1985 } 1986 } 1987 } 1988 } 1989 return result; 1990 } 1991 1992 std::optional<int> GetDummyArgumentNumber(const Symbol *symbol) { 1993 if (symbol) { 1994 if (IsDummy(*symbol)) { 1995 if (const Symbol * subpSym{symbol->owner().symbol()}) { 1996 if (const auto *subp{subpSym->detailsIf<SubprogramDetails>()}) { 1997 int j{0}; 1998 for (const Symbol *dummy : subp->dummyArgs()) { 1999 if (dummy == symbol) { 2000 return j; 2001 } 2002 ++j; 2003 } 2004 } 2005 } 2006 } 2007 } 2008 return std::nullopt; 2009 } 2010 2011 // Given a symbol that is a SubprogramNameDetails in a submodule, try to 2012 // find its interface definition in its module or ancestor submodule. 2013 const Symbol *FindAncestorModuleProcedure(const Symbol *symInSubmodule) { 2014 if (symInSubmodule && symInSubmodule->owner().IsSubmodule()) { 2015 if (const auto *nameDetails{ 2016 symInSubmodule->detailsIf<semantics::SubprogramNameDetails>()}; 2017 nameDetails && 2018 nameDetails->kind() == semantics::SubprogramKind::Module) { 2019 const Symbol *next{symInSubmodule->owner().symbol()}; 2020 while (const Symbol * submodSym{next}) { 2021 next = nullptr; 2022 if (const auto *modDetails{ 2023 submodSym->detailsIf<semantics::ModuleDetails>()}; 2024 modDetails && modDetails->isSubmodule() && modDetails->scope()) { 2025 if (const semantics::Scope & parent{modDetails->scope()->parent()}; 2026 parent.IsSubmodule() || parent.IsModule()) { 2027 if (auto iter{parent.find(symInSubmodule->name())}; 2028 iter != parent.end()) { 2029 const Symbol &proc{iter->second->GetUltimate()}; 2030 if (IsProcedure(proc)) { 2031 return &proc; 2032 } 2033 } else if (parent.IsSubmodule()) { 2034 next = parent.symbol(); 2035 } 2036 } 2037 } 2038 } 2039 } 2040 } 2041 return nullptr; 2042 } 2043 2044 } // namespace Fortran::semantics 2045