1 //===-- lib/Evaluate/type.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/type.h" 10 #include "flang/Common/idioms.h" 11 #include "flang/Common/template.h" 12 #include "flang/Evaluate/expression.h" 13 #include "flang/Evaluate/fold.h" 14 #include "flang/Parser/characters.h" 15 #include "flang/Semantics/scope.h" 16 #include "flang/Semantics/symbol.h" 17 #include "flang/Semantics/tools.h" 18 #include "flang/Semantics/type.h" 19 #include <algorithm> 20 #include <optional> 21 #include <string> 22 23 // IsDescriptor() predicate: true when a symbol is implemented 24 // at runtime with a descriptor. 25 namespace Fortran::semantics { 26 27 static bool IsDescriptor(const DeclTypeSpec *type) { 28 if (type) { 29 if (auto dynamicType{evaluate::DynamicType::From(*type)}) { 30 return dynamicType->RequiresDescriptor(); 31 } 32 } 33 return false; 34 } 35 36 static bool IsDescriptor(const ObjectEntityDetails &details) { 37 if (IsDescriptor(details.type())) { 38 return true; 39 } 40 for (const ShapeSpec &shapeSpec : details.shape()) { 41 const auto &lb{shapeSpec.lbound().GetExplicit()}; 42 const auto &ub{shapeSpec.ubound().GetExplicit()}; 43 if (!lb || !ub || !IsConstantExpr(*lb) || !IsConstantExpr(*ub)) { 44 return true; 45 } 46 } 47 return false; 48 } 49 50 static bool IsDescriptor(const ProcEntityDetails &details) { 51 // A procedure pointer or dummy procedure must be & is a descriptor if 52 // and only if it requires a static link. 53 // TODO: refine this placeholder 54 return details.HasExplicitInterface(); 55 } 56 57 bool IsDescriptor(const Symbol &symbol) { 58 return std::visit( 59 common::visitors{ 60 [&](const ObjectEntityDetails &d) { 61 return IsAllocatableOrPointer(symbol) || IsDescriptor(d); 62 }, 63 [&](const ProcEntityDetails &d) { 64 return (symbol.attrs().test(Attr::POINTER) || 65 symbol.attrs().test(Attr::EXTERNAL)) && 66 IsDescriptor(d); 67 }, 68 [&](const EntityDetails &d) { return IsDescriptor(d.type()); }, 69 [](const AssocEntityDetails &d) { 70 if (const auto &expr{d.expr()}) { 71 if (expr->Rank() > 0) { 72 return true; 73 } 74 if (const auto dynamicType{expr->GetType()}) { 75 if (dynamicType->RequiresDescriptor()) { 76 return true; 77 } 78 } 79 } 80 return false; 81 }, 82 [](const SubprogramDetails &d) { 83 return d.isFunction() && IsDescriptor(d.result()); 84 }, 85 [](const UseDetails &d) { return IsDescriptor(d.symbol()); }, 86 [](const HostAssocDetails &d) { return IsDescriptor(d.symbol()); }, 87 [](const auto &) { return false; }, 88 }, 89 symbol.details()); 90 } 91 } // namespace Fortran::semantics 92 93 namespace Fortran::evaluate { 94 95 template <typename A> inline bool PointeeComparison(const A *x, const A *y) { 96 return x == y || (x && y && *x == *y); 97 } 98 99 bool DynamicType::operator==(const DynamicType &that) const { 100 return category_ == that.category_ && kind_ == that.kind_ && 101 PointeeComparison(charLength_, that.charLength_) && 102 PointeeComparison(derived_, that.derived_); 103 } 104 105 std::optional<Expr<SubscriptInteger>> DynamicType::GetCharLength() const { 106 if (category_ == TypeCategory::Character && charLength_) { 107 if (auto length{charLength_->GetExplicit()}) { 108 return ConvertToType<SubscriptInteger>(std::move(*length)); 109 } 110 } 111 return std::nullopt; 112 } 113 114 static constexpr std::size_t RealKindBytes(int kind) { 115 switch (kind) { 116 case 3: // non-IEEE 16-bit format (truncated 32-bit) 117 return 2; 118 case 10: // 80387 80-bit extended precision 119 case 12: // possible variant spelling 120 return 16; 121 default: 122 return kind; 123 } 124 } 125 126 std::size_t DynamicType::GetAlignment(const FoldingContext &context) const { 127 switch (category_) { 128 case TypeCategory::Integer: 129 case TypeCategory::Character: 130 case TypeCategory::Logical: 131 return std::min<std::size_t>(kind_, context.maxAlignment()); 132 case TypeCategory::Real: 133 case TypeCategory::Complex: 134 return std::min(RealKindBytes(kind_), context.maxAlignment()); 135 case TypeCategory::Derived: 136 if (derived_ && derived_->scope()) { 137 return derived_->scope()->alignment().value_or(1); 138 } 139 break; 140 } 141 return 1; // needs to be after switch to dodge a bogus gcc warning 142 } 143 144 std::optional<Expr<SubscriptInteger>> DynamicType::MeasureSizeInBytes( 145 FoldingContext &context, bool aligned) const { 146 switch (category_) { 147 case TypeCategory::Integer: 148 return Expr<SubscriptInteger>{kind_}; 149 case TypeCategory::Real: 150 return Expr<SubscriptInteger>{RealKindBytes(kind_)}; 151 case TypeCategory::Complex: 152 return Expr<SubscriptInteger>{2 * RealKindBytes(kind_)}; 153 case TypeCategory::Character: 154 if (auto len{GetCharLength()}) { 155 return Fold(context, Expr<SubscriptInteger>{kind_} * std::move(*len)); 156 } 157 break; 158 case TypeCategory::Logical: 159 return Expr<SubscriptInteger>{kind_}; 160 case TypeCategory::Derived: 161 if (derived_ && derived_->scope()) { 162 auto size{derived_->scope()->size()}; 163 auto align{aligned ? derived_->scope()->alignment().value_or(0) : 0}; 164 auto alignedSize{align > 0 ? ((size + align - 1) / align) * align : size}; 165 return Expr<SubscriptInteger>{ 166 static_cast<ConstantSubscript>(alignedSize)}; 167 } 168 break; 169 } 170 return std::nullopt; 171 } 172 173 bool DynamicType::IsAssumedLengthCharacter() const { 174 return category_ == TypeCategory::Character && charLength_ && 175 charLength_->isAssumed(); 176 } 177 178 bool DynamicType::IsNonConstantLengthCharacter() const { 179 if (category_ != TypeCategory::Character) { 180 return false; 181 } else if (!charLength_) { 182 return true; 183 } else if (const auto &expr{charLength_->GetExplicit()}) { 184 return !IsConstantExpr(*expr); 185 } else { 186 return true; 187 } 188 } 189 190 bool DynamicType::IsTypelessIntrinsicArgument() const { 191 return category_ == TypeCategory::Integer && kind_ == TypelessKind; 192 } 193 194 const semantics::DerivedTypeSpec *GetDerivedTypeSpec( 195 const std::optional<DynamicType> &type) { 196 return type ? GetDerivedTypeSpec(*type) : nullptr; 197 } 198 199 const semantics::DerivedTypeSpec *GetDerivedTypeSpec(const DynamicType &type) { 200 if (type.category() == TypeCategory::Derived && 201 !type.IsUnlimitedPolymorphic()) { 202 return &type.GetDerivedTypeSpec(); 203 } else { 204 return nullptr; 205 } 206 } 207 208 static const semantics::Symbol *FindParentComponent( 209 const semantics::DerivedTypeSpec &derived) { 210 const semantics::Symbol &typeSymbol{derived.typeSymbol()}; 211 if (const semantics::Scope * scope{typeSymbol.scope()}) { 212 const auto &dtDetails{typeSymbol.get<semantics::DerivedTypeDetails>()}; 213 if (auto extends{dtDetails.GetParentComponentName()}) { 214 if (auto iter{scope->find(*extends)}; iter != scope->cend()) { 215 if (const Symbol & symbol{*iter->second}; 216 symbol.test(Symbol::Flag::ParentComp)) { 217 return &symbol; 218 } 219 } 220 } 221 } 222 return nullptr; 223 } 224 225 const semantics::DerivedTypeSpec *GetParentTypeSpec( 226 const semantics::DerivedTypeSpec &derived) { 227 if (const semantics::Symbol * parent{FindParentComponent(derived)}) { 228 return &parent->get<semantics::ObjectEntityDetails>() 229 .type() 230 ->derivedTypeSpec(); 231 } else { 232 return nullptr; 233 } 234 } 235 236 // Compares two derived type representations to see whether they both 237 // represent the "same type" in the sense of section 7.5.2.4. 238 using SetOfDerivedTypePairs = 239 std::set<std::pair<const semantics::DerivedTypeSpec *, 240 const semantics::DerivedTypeSpec *>>; 241 242 static bool AreSameComponent(const semantics::Symbol &, 243 const semantics::Symbol &, SetOfDerivedTypePairs &inProgress); 244 245 static bool AreSameDerivedType(const semantics::DerivedTypeSpec &x, 246 const semantics::DerivedTypeSpec &y, SetOfDerivedTypePairs &inProgress) { 247 const auto &xSymbol{x.typeSymbol()}; 248 const auto &ySymbol{y.typeSymbol()}; 249 if (&x == &y || xSymbol == ySymbol) { 250 return true; 251 } 252 auto thisQuery{std::make_pair(&x, &y)}; 253 if (inProgress.find(thisQuery) != inProgress.end()) { 254 return true; // recursive use of types in components 255 } 256 inProgress.insert(thisQuery); 257 const auto &xDetails{xSymbol.get<semantics::DerivedTypeDetails>()}; 258 const auto &yDetails{ySymbol.get<semantics::DerivedTypeDetails>()}; 259 if (xSymbol.name() != ySymbol.name()) { 260 return false; 261 } 262 if (!(xDetails.sequence() && yDetails.sequence()) && 263 !(xSymbol.attrs().test(semantics::Attr::BIND_C) && 264 ySymbol.attrs().test(semantics::Attr::BIND_C))) { 265 // PGI does not enforce this requirement; all other Fortran 266 // processors do with a hard error when violations are caught. 267 return false; 268 } 269 // Compare the component lists in their orders of declaration. 270 auto xEnd{xDetails.componentNames().cend()}; 271 auto yComponentName{yDetails.componentNames().cbegin()}; 272 auto yEnd{yDetails.componentNames().cend()}; 273 for (auto xComponentName{xDetails.componentNames().cbegin()}; 274 xComponentName != xEnd; ++xComponentName, ++yComponentName) { 275 if (yComponentName == yEnd || *xComponentName != *yComponentName || 276 !xSymbol.scope() || !ySymbol.scope()) { 277 return false; 278 } 279 const auto xLookup{xSymbol.scope()->find(*xComponentName)}; 280 const auto yLookup{ySymbol.scope()->find(*yComponentName)}; 281 if (xLookup == xSymbol.scope()->end() || 282 yLookup == ySymbol.scope()->end() || 283 !AreSameComponent(*xLookup->second, *yLookup->second, inProgress)) { 284 return false; 285 } 286 } 287 return yComponentName == yEnd; 288 } 289 290 static bool AreSameComponent(const semantics::Symbol &x, 291 const semantics::Symbol &y, 292 SetOfDerivedTypePairs & /* inProgress - not yet used */) { 293 if (x.attrs() != y.attrs()) { 294 return false; 295 } 296 if (x.attrs().test(semantics::Attr::PRIVATE)) { 297 return false; 298 } 299 // TODO: compare types, parameters, bounds, &c. 300 return x.has<semantics::ObjectEntityDetails>() == 301 y.has<semantics::ObjectEntityDetails>(); 302 } 303 304 static bool AreCompatibleDerivedTypes(const semantics::DerivedTypeSpec *x, 305 const semantics::DerivedTypeSpec *y, bool isPolymorphic) { 306 if (!x || !y) { 307 return false; 308 } else { 309 SetOfDerivedTypePairs inProgress; 310 if (AreSameDerivedType(*x, *y, inProgress)) { 311 return true; 312 } else { 313 return isPolymorphic && 314 AreCompatibleDerivedTypes(x, GetParentTypeSpec(*y), true); 315 } 316 } 317 } 318 319 // See 7.3.2.3 (5) & 15.5.2.4 320 bool DynamicType::IsTkCompatibleWith(const DynamicType &that) const { 321 if (IsUnlimitedPolymorphic()) { 322 return true; 323 } else if (that.IsUnlimitedPolymorphic()) { 324 return false; 325 } else if (category_ != that.category_) { 326 return false; 327 } else if (derived_) { 328 return that.derived_ && 329 AreCompatibleDerivedTypes(derived_, that.derived_, IsPolymorphic()) && 330 AreTypeParamCompatible(*derived_, *that.derived_); 331 } else { 332 return kind_ == that.kind_; 333 } 334 } 335 336 std::optional<DynamicType> DynamicType::From( 337 const semantics::DeclTypeSpec &type) { 338 if (const auto *intrinsic{type.AsIntrinsic()}) { 339 if (auto kind{ToInt64(intrinsic->kind())}) { 340 TypeCategory category{intrinsic->category()}; 341 if (IsValidKindOfIntrinsicType(category, *kind)) { 342 if (category == TypeCategory::Character) { 343 const auto &charType{type.characterTypeSpec()}; 344 return DynamicType{static_cast<int>(*kind), charType.length()}; 345 } else { 346 return DynamicType{category, static_cast<int>(*kind)}; 347 } 348 } 349 } 350 } else if (const auto *derived{type.AsDerived()}) { 351 return DynamicType{ 352 *derived, type.category() == semantics::DeclTypeSpec::ClassDerived}; 353 } else if (type.category() == semantics::DeclTypeSpec::ClassStar) { 354 return DynamicType::UnlimitedPolymorphic(); 355 } else if (type.category() == semantics::DeclTypeSpec::TypeStar) { 356 return DynamicType::AssumedType(); 357 } else { 358 common::die("DynamicType::From(DeclTypeSpec): failed"); 359 } 360 return std::nullopt; 361 } 362 363 std::optional<DynamicType> DynamicType::From(const semantics::Symbol &symbol) { 364 return From(symbol.GetType()); // Symbol -> DeclTypeSpec -> DynamicType 365 } 366 367 DynamicType DynamicType::ResultTypeForMultiply(const DynamicType &that) const { 368 switch (category_) { 369 case TypeCategory::Integer: 370 switch (that.category_) { 371 case TypeCategory::Integer: 372 return DynamicType{TypeCategory::Integer, std::max(kind_, that.kind_)}; 373 case TypeCategory::Real: 374 case TypeCategory::Complex: 375 return that; 376 default: 377 CRASH_NO_CASE; 378 } 379 break; 380 case TypeCategory::Real: 381 switch (that.category_) { 382 case TypeCategory::Integer: 383 return *this; 384 case TypeCategory::Real: 385 return DynamicType{TypeCategory::Real, std::max(kind_, that.kind_)}; 386 case TypeCategory::Complex: 387 return DynamicType{TypeCategory::Complex, std::max(kind_, that.kind_)}; 388 default: 389 CRASH_NO_CASE; 390 } 391 break; 392 case TypeCategory::Complex: 393 switch (that.category_) { 394 case TypeCategory::Integer: 395 return *this; 396 case TypeCategory::Real: 397 case TypeCategory::Complex: 398 return DynamicType{TypeCategory::Complex, std::max(kind_, that.kind_)}; 399 default: 400 CRASH_NO_CASE; 401 } 402 break; 403 case TypeCategory::Logical: 404 switch (that.category_) { 405 case TypeCategory::Logical: 406 return DynamicType{TypeCategory::Logical, std::max(kind_, that.kind_)}; 407 default: 408 CRASH_NO_CASE; 409 } 410 break; 411 default: 412 CRASH_NO_CASE; 413 } 414 return *this; 415 } 416 417 bool DynamicType::RequiresDescriptor() const { 418 return IsPolymorphic() || IsNonConstantLengthCharacter() || 419 (derived_ && CountNonConstantLenParameters(*derived_) > 0); 420 } 421 422 bool DynamicType::HasDeferredTypeParameter() const { 423 if (derived_) { 424 for (const auto &pair : derived_->parameters()) { 425 if (pair.second.isDeferred()) { 426 return true; 427 } 428 } 429 } 430 return charLength_ && charLength_->isDeferred(); 431 } 432 433 bool SomeKind<TypeCategory::Derived>::operator==( 434 const SomeKind<TypeCategory::Derived> &that) const { 435 return PointeeComparison(derivedTypeSpec_, that.derivedTypeSpec_); 436 } 437 438 int SelectedCharKind(const std::string &s, int defaultKind) { // 16.9.168 439 auto lower{parser::ToLowerCaseLetters(s)}; 440 auto n{lower.size()}; 441 while (n > 0 && lower[0] == ' ') { 442 lower.erase(0, 1); 443 --n; 444 } 445 while (n > 0 && lower[n - 1] == ' ') { 446 lower.erase(--n, 1); 447 } 448 if (lower == "ascii") { 449 return 1; 450 } else if (lower == "ucs-2") { 451 return 2; 452 } else if (lower == "iso_10646" || lower == "ucs-4") { 453 return 4; 454 } else if (lower == "default") { 455 return defaultKind; 456 } else { 457 return -1; 458 } 459 } 460 461 class SelectedIntKindVisitor { 462 public: 463 explicit SelectedIntKindVisitor(std::int64_t p) : precision_{p} {} 464 using Result = std::optional<int>; 465 using Types = IntegerTypes; 466 template <typename T> Result Test() const { 467 if (Scalar<T>::RANGE >= precision_) { 468 return T::kind; 469 } else { 470 return std::nullopt; 471 } 472 } 473 474 private: 475 std::int64_t precision_; 476 }; 477 478 int SelectedIntKind(std::int64_t precision) { 479 if (auto kind{common::SearchTypes(SelectedIntKindVisitor{precision})}) { 480 return *kind; 481 } else { 482 return -1; 483 } 484 } 485 486 class SelectedRealKindVisitor { 487 public: 488 explicit SelectedRealKindVisitor(std::int64_t p, std::int64_t r) 489 : precision_{p}, range_{r} {} 490 using Result = std::optional<int>; 491 using Types = RealTypes; 492 template <typename T> Result Test() const { 493 if (Scalar<T>::PRECISION >= precision_ && Scalar<T>::RANGE >= range_) { 494 return {T::kind}; 495 } else { 496 return std::nullopt; 497 } 498 } 499 500 private: 501 std::int64_t precision_, range_; 502 }; 503 504 int SelectedRealKind( 505 std::int64_t precision, std::int64_t range, std::int64_t radix) { 506 if (radix != 2) { 507 return -5; 508 } 509 if (auto kind{ 510 common::SearchTypes(SelectedRealKindVisitor{precision, range})}) { 511 return *kind; 512 } 513 // No kind has both sufficient precision and sufficient range. 514 // The negative return value encodes whether any kinds exist that 515 // could satisfy either constraint independently. 516 bool pOK{common::SearchTypes(SelectedRealKindVisitor{precision, 0})}; 517 bool rOK{common::SearchTypes(SelectedRealKindVisitor{0, range})}; 518 if (pOK) { 519 if (rOK) { 520 return -4; 521 } else { 522 return -2; 523 } 524 } else { 525 if (rOK) { 526 return -1; 527 } else { 528 return -3; 529 } 530 } 531 } 532 } // namespace Fortran::evaluate 533