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