164ab3302SCarolineConcatto //===-- lib/Evaluate/characteristics.cpp ----------------------------------===// 264ab3302SCarolineConcatto // 364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information. 564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 664ab3302SCarolineConcatto // 764ab3302SCarolineConcatto //===----------------------------------------------------------------------===// 864ab3302SCarolineConcatto 964ab3302SCarolineConcatto #include "flang/Evaluate/characteristics.h" 1064ab3302SCarolineConcatto #include "flang/Common/indirection.h" 1164ab3302SCarolineConcatto #include "flang/Evaluate/check-expression.h" 1264ab3302SCarolineConcatto #include "flang/Evaluate/fold.h" 1364ab3302SCarolineConcatto #include "flang/Evaluate/intrinsics.h" 1464ab3302SCarolineConcatto #include "flang/Evaluate/tools.h" 1564ab3302SCarolineConcatto #include "flang/Evaluate/type.h" 1664ab3302SCarolineConcatto #include "flang/Parser/message.h" 1764ab3302SCarolineConcatto #include "flang/Semantics/scope.h" 1864ab3302SCarolineConcatto #include "flang/Semantics/symbol.h" 1995f4ca7fSPeter Klausler #include "flang/Semantics/tools.h" 208670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h" 2164ab3302SCarolineConcatto #include <initializer_list> 2264ab3302SCarolineConcatto 2364ab3302SCarolineConcatto using namespace Fortran::parser::literals; 2464ab3302SCarolineConcatto 2564ab3302SCarolineConcatto namespace Fortran::evaluate::characteristics { 2664ab3302SCarolineConcatto 2764ab3302SCarolineConcatto // Copy attributes from a symbol to dst based on the mapping in pairs. 28f31ac3cbSPeter Klausler // An ASYNCHRONOUS attribute counts even if it is implied. 2964ab3302SCarolineConcatto template <typename A, typename B> 3064ab3302SCarolineConcatto static void CopyAttrs(const semantics::Symbol &src, A &dst, 3164ab3302SCarolineConcatto const std::initializer_list<std::pair<semantics::Attr, B>> &pairs) { 3264ab3302SCarolineConcatto for (const auto &pair : pairs) { 3364ab3302SCarolineConcatto if (src.attrs().test(pair.first)) { 3464ab3302SCarolineConcatto dst.attrs.set(pair.second); 3564ab3302SCarolineConcatto } 3664ab3302SCarolineConcatto } 3764ab3302SCarolineConcatto } 3864ab3302SCarolineConcatto 3964ab3302SCarolineConcatto // Shapes of function results and dummy arguments have to have 4064ab3302SCarolineConcatto // the same rank, the same deferred dimensions, and the same 4164ab3302SCarolineConcatto // values for explicit dimensions when constant. 4273cf0142SjeanPerier bool ShapesAreCompatible(const std::optional<Shape> &x, 4373cf0142SjeanPerier const std::optional<Shape> &y, bool *possibleWarning) { 4473cf0142SjeanPerier if (!x || !y) { 4573cf0142SjeanPerier return !x && !y; 4673cf0142SjeanPerier } 4773cf0142SjeanPerier if (x->size() != y->size()) { 4864ab3302SCarolineConcatto return false; 4964ab3302SCarolineConcatto } 5073cf0142SjeanPerier auto yIter{y->begin()}; 5173cf0142SjeanPerier for (const auto &xDim : *x) { 5264ab3302SCarolineConcatto const auto &yDim{*yIter++}; 53e86591b3SPeter Klausler if (xDim && yDim) { 54e86591b3SPeter Klausler if (auto equiv{AreEquivalentInInterface(*xDim, *yDim)}) { 55e86591b3SPeter Klausler if (!*equiv) { 5664ab3302SCarolineConcatto return false; 5764ab3302SCarolineConcatto } 58e86591b3SPeter Klausler } else if (possibleWarning) { 59e86591b3SPeter Klausler *possibleWarning = true; 60e86591b3SPeter Klausler } 61e86591b3SPeter Klausler } else if (xDim || yDim) { 6264ab3302SCarolineConcatto return false; 6364ab3302SCarolineConcatto } 6464ab3302SCarolineConcatto } 6564ab3302SCarolineConcatto return true; 6664ab3302SCarolineConcatto } 6764ab3302SCarolineConcatto 6864ab3302SCarolineConcatto bool TypeAndShape::operator==(const TypeAndShape &that) const { 69b0bdc7fcSPeter Klausler return type_.IsEquivalentTo(that.type_) && 70b0bdc7fcSPeter Klausler ShapesAreCompatible(shape_, that.shape_) && attrs_ == that.attrs_ && 71b0bdc7fcSPeter Klausler corank_ == that.corank_; 7264ab3302SCarolineConcatto } 7364ab3302SCarolineConcatto 74a50bb84eSpeter klausler TypeAndShape &TypeAndShape::Rewrite(FoldingContext &context) { 75a50bb84eSpeter klausler LEN_ = Fold(context, std::move(LEN_)); 7650960e93SPeter Klausler if (LEN_) { 7750960e93SPeter Klausler if (auto n{ToInt64(*LEN_)}) { 7850960e93SPeter Klausler type_ = DynamicType{type_.kind(), *n}; 7950960e93SPeter Klausler } 8050960e93SPeter Klausler } 81a50bb84eSpeter klausler shape_ = Fold(context, std::move(shape_)); 82a50bb84eSpeter klausler return *this; 83a50bb84eSpeter klausler } 84a50bb84eSpeter klausler 8564ab3302SCarolineConcatto std::optional<TypeAndShape> TypeAndShape::Characterize( 860c0b2ea9SPeter Klausler const semantics::Symbol &symbol, FoldingContext &context, 870c0b2ea9SPeter Klausler bool invariantOnly) { 886f3d322fSpeter klausler const auto &ultimate{symbol.GetUltimate()}; 89cd03e96fSPeter Klausler return common::visit( 9064ab3302SCarolineConcatto common::visitors{ 9164ab3302SCarolineConcatto [&](const semantics::ProcEntityDetails &proc) { 92635656f4SPeter Klausler if (proc.procInterface()) { 930c0b2ea9SPeter Klausler return Characterize( 940c0b2ea9SPeter Klausler *proc.procInterface(), context, invariantOnly); 95635656f4SPeter Klausler } else if (proc.type()) { 960c0b2ea9SPeter Klausler return Characterize(*proc.type(), context, invariantOnly); 9764ab3302SCarolineConcatto } else { 9864ab3302SCarolineConcatto return std::optional<TypeAndShape>{}; 9964ab3302SCarolineConcatto } 10064ab3302SCarolineConcatto }, 10164ab3302SCarolineConcatto [&](const semantics::AssocEntityDetails &assoc) { 1020c0b2ea9SPeter Klausler return Characterize(assoc, context, invariantOnly); 10364ab3302SCarolineConcatto }, 1040996b590Speter klausler [&](const semantics::ProcBindingDetails &binding) { 1050c0b2ea9SPeter Klausler return Characterize(binding.symbol(), context, invariantOnly); 1060996b590Speter klausler }, 10773c3530fSpeter klausler [&](const auto &x) -> std::optional<TypeAndShape> { 10873c3530fSpeter klausler using Ty = std::decay_t<decltype(x)>; 10973c3530fSpeter klausler if constexpr (std::is_same_v<Ty, semantics::EntityDetails> || 11073c3530fSpeter klausler std::is_same_v<Ty, semantics::ObjectEntityDetails> || 11173c3530fSpeter klausler std::is_same_v<Ty, semantics::TypeParamDetails>) { 11273c3530fSpeter klausler if (const semantics::DeclTypeSpec * type{ultimate.GetType()}) { 11373c3530fSpeter klausler if (auto dyType{DynamicType::From(*type)}) { 1140c0b2ea9SPeter Klausler TypeAndShape result{std::move(*dyType), 1150c0b2ea9SPeter Klausler GetShape(context, ultimate, invariantOnly)}; 11673c3530fSpeter klausler result.AcquireAttrs(ultimate); 11773c3530fSpeter klausler result.AcquireLEN(ultimate); 11873c3530fSpeter klausler return std::move(result.Rewrite(context)); 11973c3530fSpeter klausler } 12073c3530fSpeter klausler } 12173c3530fSpeter klausler } 12273c3530fSpeter klausler return std::nullopt; 12373c3530fSpeter klausler }, 12464ab3302SCarolineConcatto }, 125a50bb84eSpeter klausler // GetUltimate() used here, not ResolveAssociations(), because 126a50bb84eSpeter klausler // we need the type/rank of an associate entity from TYPE IS, 127a50bb84eSpeter klausler // CLASS IS, or RANK statement. 1286f3d322fSpeter klausler ultimate.details()); 12964ab3302SCarolineConcatto } 13064ab3302SCarolineConcatto 13164ab3302SCarolineConcatto std::optional<TypeAndShape> TypeAndShape::Characterize( 1320c0b2ea9SPeter Klausler const semantics::AssocEntityDetails &assoc, FoldingContext &context, 1330c0b2ea9SPeter Klausler bool invariantOnly) { 134a50bb84eSpeter klausler std::optional<TypeAndShape> result; 13564ab3302SCarolineConcatto if (auto type{DynamicType::From(assoc.type())}) { 136a50bb84eSpeter klausler if (auto rank{assoc.rank()}) { 137a50bb84eSpeter klausler if (*rank >= 0 && *rank <= common::maxRank) { 138a50bb84eSpeter klausler result = TypeAndShape{std::move(*type), Shape(*rank)}; 139a50bb84eSpeter klausler } 1400c0b2ea9SPeter Klausler } else if (auto shape{GetShape(context, assoc.expr(), invariantOnly)}) { 141a50bb84eSpeter klausler result = TypeAndShape{std::move(*type), std::move(*shape)}; 142a50bb84eSpeter klausler } 143a50bb84eSpeter klausler if (result && type->category() == TypeCategory::Character) { 14453bf28b8Speter klausler if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(assoc.expr())}) { 14553bf28b8Speter klausler if (auto len{chExpr->LEN()}) { 146a50bb84eSpeter klausler result->set_LEN(std::move(*len)); 14753bf28b8Speter klausler } 14853bf28b8Speter klausler } 14953bf28b8Speter klausler } 15064ab3302SCarolineConcatto } 151a50bb84eSpeter klausler return Fold(context, std::move(result)); 15264ab3302SCarolineConcatto } 15364ab3302SCarolineConcatto 15464ab3302SCarolineConcatto std::optional<TypeAndShape> TypeAndShape::Characterize( 1550c0b2ea9SPeter Klausler const semantics::DeclTypeSpec &spec, FoldingContext &context, 1560c0b2ea9SPeter Klausler bool /*invariantOnly=*/) { 15764ab3302SCarolineConcatto if (auto type{DynamicType::From(spec)}) { 158a50bb84eSpeter klausler return Fold(context, TypeAndShape{std::move(*type)}); 15964ab3302SCarolineConcatto } else { 16064ab3302SCarolineConcatto return std::nullopt; 16164ab3302SCarolineConcatto } 16264ab3302SCarolineConcatto } 16364ab3302SCarolineConcatto 164fad31d60Speter klausler std::optional<TypeAndShape> TypeAndShape::Characterize( 1650c0b2ea9SPeter Klausler const ActualArgument &arg, FoldingContext &context, bool invariantOnly) { 166a88cee1fSPeter Klausler if (const auto *expr{arg.UnwrapExpr()}) { 1670c0b2ea9SPeter Klausler return Characterize(*expr, context, invariantOnly); 168a88cee1fSPeter Klausler } else if (const Symbol * assumed{arg.GetAssumedTypeDummy()}) { 1690c0b2ea9SPeter Klausler return Characterize(*assumed, context, invariantOnly); 170a88cee1fSPeter Klausler } else { 171a88cee1fSPeter Klausler return std::nullopt; 172a88cee1fSPeter Klausler } 173fad31d60Speter klausler } 174fad31d60Speter klausler 17564ab3302SCarolineConcatto bool TypeAndShape::IsCompatibleWith(parser::ContextualMessages &messages, 17664ab3302SCarolineConcatto const TypeAndShape &that, const char *thisIs, const char *thatIs, 1777763c014SPeter Klausler bool omitShapeConformanceCheck, 1787763c014SPeter Klausler enum CheckConformanceFlags::Flags flags) const { 17937b2e2b0Speter klausler if (!type_.IsTkCompatibleWith(that.type_)) { 18064ab3302SCarolineConcatto messages.Say( 18164ab3302SCarolineConcatto "%1$s type '%2$s' is not compatible with %3$s type '%4$s'"_err_en_US, 182b82a8c3fSpeter klausler thatIs, that.AsFortran(), thisIs, AsFortran()); 18364ab3302SCarolineConcatto return false; 18464ab3302SCarolineConcatto } 18573cf0142SjeanPerier return omitShapeConformanceCheck || (!shape_ && !that.shape_) || 18673cf0142SjeanPerier (shape_ && that.shape_ && 18773cf0142SjeanPerier CheckConformance( 18873cf0142SjeanPerier messages, *shape_, *that.shape_, flags, thisIs, thatIs) 18973cf0142SjeanPerier .value_or(true /*fail only when nonconformance is known now*/)); 19064ab3302SCarolineConcatto } 19164ab3302SCarolineConcatto 192efc5926cSpeter klausler std::optional<Expr<SubscriptInteger>> TypeAndShape::MeasureElementSizeInBytes( 193efc5926cSpeter klausler FoldingContext &foldingContext, bool align) const { 194efc5926cSpeter klausler if (LEN_) { 195efc5926cSpeter klausler CHECK(type_.category() == TypeCategory::Character); 196efc5926cSpeter klausler return Fold(foldingContext, 19723c2bedfSPeter Klausler Expr<SubscriptInteger>{ 19823c2bedfSPeter Klausler foldingContext.targetCharacteristics().GetByteSize( 19923c2bedfSPeter Klausler type_.category(), type_.kind())} * 20023c2bedfSPeter Klausler Expr<SubscriptInteger>{*LEN_}); 201efc5926cSpeter klausler } 202efc5926cSpeter klausler if (auto elementBytes{type_.MeasureSizeInBytes(foldingContext, align)}) { 203efc5926cSpeter klausler return Fold(foldingContext, std::move(*elementBytes)); 204efc5926cSpeter klausler } 205efc5926cSpeter klausler return std::nullopt; 206efc5926cSpeter klausler } 207efc5926cSpeter klausler 20853bf28b8Speter klausler std::optional<Expr<SubscriptInteger>> TypeAndShape::MeasureSizeInBytes( 2096aa3591eSpeter klausler FoldingContext &foldingContext) const { 21073cf0142SjeanPerier if (auto elements{GetSize(shape_)}) { 2116aa3591eSpeter klausler // Sizes of arrays (even with single elements) are multiples of 2126aa3591eSpeter klausler // their alignments. 2136aa3591eSpeter klausler if (auto elementBytes{ 21473cf0142SjeanPerier MeasureElementSizeInBytes(foldingContext, Rank() > 0)}) { 2156aa3591eSpeter klausler return Fold( 2166aa3591eSpeter klausler foldingContext, std::move(*elements) * std::move(*elementBytes)); 21753bf28b8Speter klausler } 21853bf28b8Speter klausler } 2196aa3591eSpeter klausler return std::nullopt; 22053bf28b8Speter klausler } 22153bf28b8Speter klausler 2226f3d322fSpeter klausler void TypeAndShape::AcquireAttrs(const semantics::Symbol &symbol) { 22344bc97c8SPeter Klausler if (IsAssumedShape(symbol)) { 22444bc97c8SPeter Klausler attrs_.set(Attr::AssumedShape); 2257b801233SPeter Klausler } else if (IsDeferredShape(symbol)) { 22644bc97c8SPeter Klausler attrs_.set(Attr::DeferredShape); 2277b801233SPeter Klausler } else if (semantics::IsAssumedSizeArray(symbol)) { 2287b801233SPeter Klausler attrs_.set(Attr::AssumedSize); 22944bc97c8SPeter Klausler } 230*d732c86cSPeter Klausler if (int corank{GetCorank(symbol)}; corank > 0) { 231*d732c86cSPeter Klausler corank_ = corank; 23264ab3302SCarolineConcatto } 2333a8a52f4SPeter Klausler if (const auto *object{ 2343a8a52f4SPeter Klausler symbol.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()}; 2353a8a52f4SPeter Klausler object && object->IsAssumedRank()) { 2363a8a52f4SPeter Klausler attrs_.set(Attr::AssumedRank); 23764ab3302SCarolineConcatto } 23864ab3302SCarolineConcatto } 23964ab3302SCarolineConcatto 24064ab3302SCarolineConcatto void TypeAndShape::AcquireLEN() { 241ac964175Speter klausler if (auto len{type_.GetCharLength()}) { 242ac964175Speter klausler LEN_ = std::move(len); 24364ab3302SCarolineConcatto } 24464ab3302SCarolineConcatto } 24564ab3302SCarolineConcatto 2466f3d322fSpeter klausler void TypeAndShape::AcquireLEN(const semantics::Symbol &symbol) { 2476f3d322fSpeter klausler if (type_.category() == TypeCategory::Character) { 2486f3d322fSpeter klausler if (auto len{DataRef{symbol}.LEN()}) { 2496f3d322fSpeter klausler LEN_ = std::move(*len); 2506f3d322fSpeter klausler } 2516f3d322fSpeter klausler } 2526f3d322fSpeter klausler } 2536f3d322fSpeter klausler 254b82a8c3fSpeter klausler std::string TypeAndShape::AsFortran() const { 255b82a8c3fSpeter klausler return type_.AsFortran(LEN_ ? LEN_->AsFortran() : ""); 256b82a8c3fSpeter klausler } 257b82a8c3fSpeter klausler 2588670e499SCaroline Concatto llvm::raw_ostream &TypeAndShape::Dump(llvm::raw_ostream &o) const { 25964ab3302SCarolineConcatto o << type_.AsFortran(LEN_ ? LEN_->AsFortran() : ""); 26064ab3302SCarolineConcatto attrs_.Dump(o, EnumToString); 26173cf0142SjeanPerier if (!shape_) { 26273cf0142SjeanPerier o << " dimension(..)"; 26373cf0142SjeanPerier } else if (!shape_->empty()) { 264fad31d60Speter klausler o << " dimension"; 26564ab3302SCarolineConcatto char sep{'('}; 26673cf0142SjeanPerier for (const auto &expr : *shape_) { 26764ab3302SCarolineConcatto o << sep; 26864ab3302SCarolineConcatto sep = ','; 26964ab3302SCarolineConcatto if (expr) { 27064ab3302SCarolineConcatto expr->AsFortran(o); 27164ab3302SCarolineConcatto } else { 27264ab3302SCarolineConcatto o << ':'; 27364ab3302SCarolineConcatto } 27464ab3302SCarolineConcatto } 27564ab3302SCarolineConcatto o << ')'; 27664ab3302SCarolineConcatto } 27764ab3302SCarolineConcatto return o; 27864ab3302SCarolineConcatto } 27964ab3302SCarolineConcatto 28064ab3302SCarolineConcatto bool DummyDataObject::operator==(const DummyDataObject &that) const { 28164ab3302SCarolineConcatto return type == that.type && attrs == that.attrs && intent == that.intent && 282f513bd80SPeter Klausler coshape == that.coshape && cudaDataAttr == that.cudaDataAttr; 28364ab3302SCarolineConcatto } 28464ab3302SCarolineConcatto 285e86591b3SPeter Klausler bool DummyDataObject::IsCompatibleWith(const DummyDataObject &actual, 286e86591b3SPeter Klausler std::string *whyNot, std::optional<std::string> *warning) const { 287e86591b3SPeter Klausler bool possibleWarning{false}; 288e86591b3SPeter Klausler if (!ShapesAreCompatible( 289e86591b3SPeter Klausler type.shape(), actual.type.shape(), &possibleWarning)) { 29062d874f2SPeter Klausler if (whyNot) { 29162d874f2SPeter Klausler *whyNot = "incompatible dummy data object shapes"; 29262d874f2SPeter Klausler } 29362d874f2SPeter Klausler return false; 294e86591b3SPeter Klausler } else if (warning && possibleWarning) { 295e86591b3SPeter Klausler *warning = "distinct dummy data object shapes"; 29662d874f2SPeter Klausler } 297c7040509SPeter Klausler // Treat deduced dummy character type as if it were assumed-length character 298c7040509SPeter Klausler // to avoid useless "implicit interfaces have distinct type" warnings from 299c7040509SPeter Klausler // CALL FOO('abc'); CALL FOO('abcd'). 300c7040509SPeter Klausler bool deducedAssumedLength{type.type().category() == TypeCategory::Character && 301c7040509SPeter Klausler attrs.test(Attr::DeducedFromActual)}; 302c7040509SPeter Klausler bool compatibleTypes{deducedAssumedLength 303c7040509SPeter Klausler ? type.type().IsTkCompatibleWith(actual.type.type()) 304c7040509SPeter Klausler : type.type().IsTkLenCompatibleWith(actual.type.type())}; 305c7040509SPeter Klausler if (!compatibleTypes) { 30662d874f2SPeter Klausler if (whyNot) { 30762d874f2SPeter Klausler *whyNot = "incompatible dummy data object types: "s + 30862d874f2SPeter Klausler type.type().AsFortran() + " vs " + actual.type.type().AsFortran(); 30962d874f2SPeter Klausler } 31062d874f2SPeter Klausler return false; 31162d874f2SPeter Klausler } 312f7e43041SPeter Klausler if (type.type().IsPolymorphic() != actual.type.type().IsPolymorphic()) { 313f7e43041SPeter Klausler if (whyNot) { 314f7e43041SPeter Klausler *whyNot = "incompatible dummy data object polymorphism: "s + 315f7e43041SPeter Klausler type.type().AsFortran() + " vs " + actual.type.type().AsFortran(); 316f7e43041SPeter Klausler } 317f7e43041SPeter Klausler return false; 318f7e43041SPeter Klausler } 319c7040509SPeter Klausler if (type.type().category() == TypeCategory::Character && 320c7040509SPeter Klausler !deducedAssumedLength) { 3216ceba01aSPeter Klausler if (actual.type.type().IsAssumedLengthCharacter() != 3226ceba01aSPeter Klausler type.type().IsAssumedLengthCharacter()) { 3236ceba01aSPeter Klausler if (whyNot) { 3246ceba01aSPeter Klausler *whyNot = "assumed-length character vs explicit-length character"; 3256ceba01aSPeter Klausler } 3266ceba01aSPeter Klausler return false; 3276ceba01aSPeter Klausler } 3286ceba01aSPeter Klausler if (!type.type().IsAssumedLengthCharacter() && type.LEN() && 3296ceba01aSPeter Klausler actual.type.LEN()) { 3306ceba01aSPeter Klausler auto len{ToInt64(*type.LEN())}; 3316ceba01aSPeter Klausler auto actualLen{ToInt64(*actual.type.LEN())}; 3326ceba01aSPeter Klausler if (len.has_value() != actualLen.has_value()) { 3336ceba01aSPeter Klausler if (whyNot) { 3346ceba01aSPeter Klausler *whyNot = "constant-length vs non-constant-length character dummy " 3356ceba01aSPeter Klausler "arguments"; 3366ceba01aSPeter Klausler } 3376ceba01aSPeter Klausler return false; 3386ceba01aSPeter Klausler } else if (len && *len != *actualLen) { 3396ceba01aSPeter Klausler if (whyNot) { 3406ceba01aSPeter Klausler *whyNot = "character dummy arguments with distinct lengths"; 3416ceba01aSPeter Klausler } 3426ceba01aSPeter Klausler return false; 3436ceba01aSPeter Klausler } 3446ceba01aSPeter Klausler } 3456ceba01aSPeter Klausler } 3465718a425SPeter Klausler if (!IdenticalSignificantAttrs(attrs, actual.attrs) || 3475718a425SPeter Klausler type.attrs() != actual.type.attrs()) { 34862d874f2SPeter Klausler if (whyNot) { 34962d874f2SPeter Klausler *whyNot = "incompatible dummy data object attributes"; 35062d874f2SPeter Klausler } 35162d874f2SPeter Klausler return false; 35262d874f2SPeter Klausler } 35362d874f2SPeter Klausler if (intent != actual.intent) { 35462d874f2SPeter Klausler if (whyNot) { 35562d874f2SPeter Klausler *whyNot = "incompatible dummy data object intents"; 35662d874f2SPeter Klausler } 35762d874f2SPeter Klausler return false; 35862d874f2SPeter Klausler } 35962d874f2SPeter Klausler if (coshape != actual.coshape) { 36062d874f2SPeter Klausler if (whyNot) { 36162d874f2SPeter Klausler *whyNot = "incompatible dummy data object coshapes"; 36262d874f2SPeter Klausler } 36362d874f2SPeter Klausler return false; 36462d874f2SPeter Klausler } 365864cb2aaSPeter Klausler if (ignoreTKR != actual.ignoreTKR) { 366864cb2aaSPeter Klausler if (whyNot) { 367864cb2aaSPeter Klausler *whyNot = "incompatible !DIR$ IGNORE_TKR directives"; 368864cb2aaSPeter Klausler } 369864cb2aaSPeter Klausler } 370f513bd80SPeter Klausler if (!attrs.test(Attr::Value) && 3713e930864SValentin Clement !common::AreCompatibleCUDADataAttrs(cudaDataAttr, actual.cudaDataAttr, 37230d80009SValentin Clement (バレンタイン クレメン) ignoreTKR, warning, 3733e930864SValentin Clement /*allowUnifiedMatchingRule=*/false)) { 374f513bd80SPeter Klausler if (whyNot) { 375f513bd80SPeter Klausler *whyNot = "incompatible CUDA data attributes"; 376f513bd80SPeter Klausler } 377f513bd80SPeter Klausler } 37862d874f2SPeter Klausler return true; 3793bfe9074SPeter Klausler } 3803bfe9074SPeter Klausler 38164ab3302SCarolineConcatto static common::Intent GetIntent(const semantics::Attrs &attrs) { 38264ab3302SCarolineConcatto if (attrs.test(semantics::Attr::INTENT_IN)) { 38364ab3302SCarolineConcatto return common::Intent::In; 38464ab3302SCarolineConcatto } else if (attrs.test(semantics::Attr::INTENT_OUT)) { 38564ab3302SCarolineConcatto return common::Intent::Out; 38664ab3302SCarolineConcatto } else if (attrs.test(semantics::Attr::INTENT_INOUT)) { 38764ab3302SCarolineConcatto return common::Intent::InOut; 38864ab3302SCarolineConcatto } else { 38964ab3302SCarolineConcatto return common::Intent::Default; 39064ab3302SCarolineConcatto } 39164ab3302SCarolineConcatto } 39264ab3302SCarolineConcatto 39364ab3302SCarolineConcatto std::optional<DummyDataObject> DummyDataObject::Characterize( 394641ede93Speter klausler const semantics::Symbol &symbol, FoldingContext &context) { 395864cb2aaSPeter Klausler if (const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()}; 396864cb2aaSPeter Klausler object || symbol.has<semantics::EntityDetails>()) { 3970c0b2ea9SPeter Klausler if (auto type{TypeAndShape::Characterize( 3980c0b2ea9SPeter Klausler symbol, context, /*invariantOnly=*/false)}) { 39964ab3302SCarolineConcatto std::optional<DummyDataObject> result{std::move(*type)}; 40064ab3302SCarolineConcatto using semantics::Attr; 40164ab3302SCarolineConcatto CopyAttrs<DummyDataObject, DummyDataObject::Attr>(symbol, *result, 40264ab3302SCarolineConcatto { 40364ab3302SCarolineConcatto {Attr::OPTIONAL, DummyDataObject::Attr::Optional}, 40464ab3302SCarolineConcatto {Attr::ALLOCATABLE, DummyDataObject::Attr::Allocatable}, 40564ab3302SCarolineConcatto {Attr::ASYNCHRONOUS, DummyDataObject::Attr::Asynchronous}, 40664ab3302SCarolineConcatto {Attr::CONTIGUOUS, DummyDataObject::Attr::Contiguous}, 40764ab3302SCarolineConcatto {Attr::VALUE, DummyDataObject::Attr::Value}, 40864ab3302SCarolineConcatto {Attr::VOLATILE, DummyDataObject::Attr::Volatile}, 40964ab3302SCarolineConcatto {Attr::POINTER, DummyDataObject::Attr::Pointer}, 41064ab3302SCarolineConcatto {Attr::TARGET, DummyDataObject::Attr::Target}, 41164ab3302SCarolineConcatto }); 41264ab3302SCarolineConcatto result->intent = GetIntent(symbol.attrs()); 413864cb2aaSPeter Klausler result->ignoreTKR = GetIgnoreTKR(symbol); 414f513bd80SPeter Klausler if (object) { 415f513bd80SPeter Klausler result->cudaDataAttr = object->cudaDataAttr(); 416f513bd80SPeter Klausler if (!result->cudaDataAttr && 417f513bd80SPeter Klausler !result->attrs.test(DummyDataObject::Attr::Value) && 418f513bd80SPeter Klausler semantics::IsCUDADeviceContext(&symbol.owner())) { 419f513bd80SPeter Klausler result->cudaDataAttr = common::CUDADataAttr::Device; 420f513bd80SPeter Klausler } 421f513bd80SPeter Klausler } 42264ab3302SCarolineConcatto return result; 42364ab3302SCarolineConcatto } 42464ab3302SCarolineConcatto } 42564ab3302SCarolineConcatto return std::nullopt; 42664ab3302SCarolineConcatto } 42764ab3302SCarolineConcatto 4286e0a2031SPeter Klausler bool DummyDataObject::CanBePassedViaImplicitInterface( 4296e0a2031SPeter Klausler std::string *whyNot) const { 43064ab3302SCarolineConcatto if ((attrs & 43164ab3302SCarolineConcatto Attrs{Attr::Allocatable, Attr::Asynchronous, Attr::Optional, 43264ab3302SCarolineConcatto Attr::Pointer, Attr::Target, Attr::Value, Attr::Volatile}) 43364ab3302SCarolineConcatto .any()) { 4346e0a2031SPeter Klausler if (whyNot) { 4356e0a2031SPeter Klausler *whyNot = "a dummy argument has the allocatable, asynchronous, optional, " 4366e0a2031SPeter Klausler "pointer, target, value, or volatile attribute"; 4376e0a2031SPeter Klausler } 43864ab3302SCarolineConcatto return false; // 15.4.2.2(3)(a) 43964ab3302SCarolineConcatto } else if ((type.attrs() & 44064ab3302SCarolineConcatto TypeAndShape::Attrs{TypeAndShape::Attr::AssumedShape, 441*d732c86cSPeter Klausler TypeAndShape::Attr::AssumedRank}) 442*d732c86cSPeter Klausler .any() || 443*d732c86cSPeter Klausler type.corank() > 0) { 4446e0a2031SPeter Klausler if (whyNot) { 4456e0a2031SPeter Klausler *whyNot = "a dummy argument is assumed-shape, assumed-rank, or a coarray"; 4466e0a2031SPeter Klausler } 44764ab3302SCarolineConcatto return false; // 15.4.2.2(3)(b-d) 44864ab3302SCarolineConcatto } else if (type.type().IsPolymorphic()) { 4496e0a2031SPeter Klausler if (whyNot) { 4506e0a2031SPeter Klausler *whyNot = "a dummy argument is polymorphic"; 4516e0a2031SPeter Klausler } 45264ab3302SCarolineConcatto return false; // 15.4.2.2(3)(f) 453f513bd80SPeter Klausler } else if (cudaDataAttr) { 4546e0a2031SPeter Klausler if (whyNot) { 4556e0a2031SPeter Klausler *whyNot = "a dummy argument has a CUDA data attribute"; 4566e0a2031SPeter Klausler } 457f513bd80SPeter Klausler return false; 45864ab3302SCarolineConcatto } else if (const auto *derived{GetDerivedTypeSpec(type.type())}) { 4596e0a2031SPeter Klausler if (derived->parameters().empty()) { // 15.4.2.2(3)(e) 4606e0a2031SPeter Klausler return true; 4616e0a2031SPeter Klausler } else { 4626e0a2031SPeter Klausler if (whyNot) { 4636e0a2031SPeter Klausler *whyNot = "a dummy argument has derived type parameters"; 4646e0a2031SPeter Klausler } 4656e0a2031SPeter Klausler return false; 4666e0a2031SPeter Klausler } 46764ab3302SCarolineConcatto } else { 46864ab3302SCarolineConcatto return true; 46964ab3302SCarolineConcatto } 47064ab3302SCarolineConcatto } 47164ab3302SCarolineConcatto 472b477d39bSjeanPerier bool DummyDataObject::IsPassedByDescriptor(bool isBindC) const { 473*d732c86cSPeter Klausler constexpr TypeAndShape::Attrs shapeRequiringBox{ 474b477d39bSjeanPerier TypeAndShape::Attr::AssumedShape, TypeAndShape::Attr::DeferredShape, 475*d732c86cSPeter Klausler TypeAndShape::Attr::AssumedRank}; 476b477d39bSjeanPerier if ((attrs & Attrs{Attr::Allocatable, Attr::Pointer}).any()) { 477b477d39bSjeanPerier return true; 478b477d39bSjeanPerier } else if ((type.attrs() & shapeRequiringBox).any()) { 479*d732c86cSPeter Klausler return true; // pass shape in descriptor 480*d732c86cSPeter Klausler } else if (type.corank() > 0) { 481*d732c86cSPeter Klausler return true; // pass coshape in descriptor 482b477d39bSjeanPerier } else if (type.type().IsPolymorphic() && !type.type().IsAssumedType()) { 483b477d39bSjeanPerier // Need to pass dynamic type info in a descriptor. 484b477d39bSjeanPerier return true; 485b477d39bSjeanPerier } else if (const auto *derived{GetDerivedTypeSpec(type.type())}) { 48638b54c72SJean Perier if (!derived->parameters().empty()) { 48738b54c72SJean Perier for (const auto ¶m : derived->parameters()) { 48838b54c72SJean Perier if (param.second.isLen()) { 48938b54c72SJean Perier // Need to pass length type parameters in a descriptor. 49038b54c72SJean Perier return true; 49138b54c72SJean Perier } 49238b54c72SJean Perier } 493b477d39bSjeanPerier } 494b477d39bSjeanPerier } else if (isBindC && type.type().IsAssumedLengthCharacter()) { 495b477d39bSjeanPerier // Fortran 2018 18.3.6 point 2 (5) 496b477d39bSjeanPerier return true; 497b477d39bSjeanPerier } 498b477d39bSjeanPerier return false; 499b477d39bSjeanPerier } 500b477d39bSjeanPerier 5018670e499SCaroline Concatto llvm::raw_ostream &DummyDataObject::Dump(llvm::raw_ostream &o) const { 50264ab3302SCarolineConcatto attrs.Dump(o, EnumToString); 50364ab3302SCarolineConcatto if (intent != common::Intent::Default) { 50464ab3302SCarolineConcatto o << "INTENT(" << common::EnumToString(intent) << ')'; 50564ab3302SCarolineConcatto } 50664ab3302SCarolineConcatto type.Dump(o); 50764ab3302SCarolineConcatto if (!coshape.empty()) { 50864ab3302SCarolineConcatto char sep{'['}; 50964ab3302SCarolineConcatto for (const auto &expr : coshape) { 51064ab3302SCarolineConcatto expr.AsFortran(o << sep); 51164ab3302SCarolineConcatto sep = ','; 51264ab3302SCarolineConcatto } 51364ab3302SCarolineConcatto } 514f513bd80SPeter Klausler if (cudaDataAttr) { 515f513bd80SPeter Klausler o << " cudaDataAttr: " << common::EnumToString(*cudaDataAttr); 516f513bd80SPeter Klausler } 517e5ccfbbfSPeter Klausler if (!ignoreTKR.empty()) { 518e5ccfbbfSPeter Klausler ignoreTKR.Dump(o << ' ', common::EnumToString); 519e5ccfbbfSPeter Klausler } 52064ab3302SCarolineConcatto return o; 52164ab3302SCarolineConcatto } 52264ab3302SCarolineConcatto 52364ab3302SCarolineConcatto DummyProcedure::DummyProcedure(Procedure &&p) 52464ab3302SCarolineConcatto : procedure{new Procedure{std::move(p)}} {} 52564ab3302SCarolineConcatto 52664ab3302SCarolineConcatto bool DummyProcedure::operator==(const DummyProcedure &that) const { 52764ab3302SCarolineConcatto return attrs == that.attrs && intent == that.intent && 52864ab3302SCarolineConcatto procedure.value() == that.procedure.value(); 52964ab3302SCarolineConcatto } 53064ab3302SCarolineConcatto 53162d874f2SPeter Klausler bool DummyProcedure::IsCompatibleWith( 53262d874f2SPeter Klausler const DummyProcedure &actual, std::string *whyNot) const { 53362d874f2SPeter Klausler if (attrs != actual.attrs) { 53462d874f2SPeter Klausler if (whyNot) { 53562d874f2SPeter Klausler *whyNot = "incompatible dummy procedure attributes"; 53662d874f2SPeter Klausler } 53762d874f2SPeter Klausler return false; 53862d874f2SPeter Klausler } 53962d874f2SPeter Klausler if (intent != actual.intent) { 54062d874f2SPeter Klausler if (whyNot) { 54162d874f2SPeter Klausler *whyNot = "incompatible dummy procedure intents"; 54262d874f2SPeter Klausler } 54362d874f2SPeter Klausler return false; 54462d874f2SPeter Klausler } 5451c530b3dSPeter Klausler if (!procedure.value().IsCompatibleWith(actual.procedure.value(), 5461c530b3dSPeter Klausler /*ignoreImplicitVsExplicit=*/false, whyNot)) { 54762d874f2SPeter Klausler if (whyNot) { 54862d874f2SPeter Klausler *whyNot = "incompatible dummy procedure interfaces: "s + *whyNot; 54962d874f2SPeter Klausler } 55062d874f2SPeter Klausler return false; 55162d874f2SPeter Klausler } 55262d874f2SPeter Klausler return true; 5533bfe9074SPeter Klausler } 5543bfe9074SPeter Klausler 5556e0a2031SPeter Klausler bool DummyProcedure::CanBePassedViaImplicitInterface( 5566e0a2031SPeter Klausler std::string *whyNot) const { 55766fdfff7SPeter Klausler if ((attrs & Attrs{Attr::Optional, Attr::Pointer}).any()) { 5586e0a2031SPeter Klausler if (whyNot) { 5596e0a2031SPeter Klausler *whyNot = "a dummy procedure is optional or a pointer"; 5606e0a2031SPeter Klausler } 56166fdfff7SPeter Klausler return false; // 15.4.2.2(3)(a) 56266fdfff7SPeter Klausler } 56366fdfff7SPeter Klausler return true; 56466fdfff7SPeter Klausler } 56566fdfff7SPeter Klausler 5660d8331c0Speter klausler static std::string GetSeenProcs( 5670d8331c0Speter klausler const semantics::UnorderedSymbolSet &seenProcs) { 56895540f9dSPeter Steinfeld // Sort the symbols so that they appear in the same order on all platforms 5690d8331c0Speter klausler auto ordered{semantics::OrderBySourcePosition(seenProcs)}; 57077dc203cSPeter Steinfeld std::string result; 57177dc203cSPeter Steinfeld llvm::interleave( 5720d8331c0Speter klausler ordered, 57377dc203cSPeter Steinfeld [&](const SymbolRef p) { result += '\'' + p->name().ToString() + '\''; }, 57477dc203cSPeter Steinfeld [&]() { result += ", "; }); 57577dc203cSPeter Steinfeld return result; 57677dc203cSPeter Steinfeld } 57777dc203cSPeter Steinfeld 5780d8331c0Speter klausler // These functions with arguments of type UnorderedSymbolSet are used with 5790d8331c0Speter klausler // mutually recursive calls when characterizing a Procedure, a DummyArgument, 5800d8331c0Speter klausler // or a DummyProcedure to detect circularly defined procedures as required by 58177dc203cSPeter Steinfeld // 15.4.3.6, paragraph 2. 58277dc203cSPeter Steinfeld static std::optional<DummyArgument> CharacterizeDummyArgument( 58377dc203cSPeter Steinfeld const semantics::Symbol &symbol, FoldingContext &context, 584174cabedSPeter Klausler semantics::UnorderedSymbolSet seenProcs); 585488b9fd1SDaniil Dudkin static std::optional<FunctionResult> CharacterizeFunctionResult( 586488b9fd1SDaniil Dudkin const semantics::Symbol &symbol, FoldingContext &context, 587cb263919SPeter Klausler semantics::UnorderedSymbolSet seenProcs, bool emitError); 58877dc203cSPeter Steinfeld 58977dc203cSPeter Steinfeld static std::optional<Procedure> CharacterizeProcedure( 59077dc203cSPeter Steinfeld const semantics::Symbol &original, FoldingContext &context, 591cb263919SPeter Klausler semantics::UnorderedSymbolSet seenProcs, bool emitError) { 592f8f70028Speter klausler const auto &symbol{ResolveAssociations(original)}; 59377dc203cSPeter Steinfeld if (seenProcs.find(symbol) != seenProcs.end()) { 59477dc203cSPeter Steinfeld std::string procsList{GetSeenProcs(seenProcs)}; 59577dc203cSPeter Steinfeld context.messages().Say(symbol.name(), 59677dc203cSPeter Steinfeld "Procedure '%s' is recursively defined. Procedures in the cycle:" 59795540f9dSPeter Steinfeld " %s"_err_en_US, 59877dc203cSPeter Steinfeld symbol.name(), procsList); 59977dc203cSPeter Steinfeld return std::nullopt; 60077dc203cSPeter Steinfeld } 60177dc203cSPeter Steinfeld seenProcs.insert(symbol); 602cb263919SPeter Klausler auto CheckForNested{[&](const Symbol &symbol) { 603cb263919SPeter Klausler if (emitError) { 604cb263919SPeter Klausler context.messages().Say( 605cb263919SPeter Klausler "Procedure '%s' is referenced before being sufficiently defined in a context where it must be so"_err_en_US, 606cb263919SPeter Klausler symbol.name()); 607cb263919SPeter Klausler } 608cb263919SPeter Klausler }}; 6090c0b2ea9SPeter Klausler auto result{common::visit( 61077dc203cSPeter Steinfeld common::visitors{ 61177dc203cSPeter Steinfeld [&](const semantics::SubprogramDetails &subp) 61277dc203cSPeter Steinfeld -> std::optional<Procedure> { 6130c0b2ea9SPeter Klausler Procedure result; 61477dc203cSPeter Steinfeld if (subp.isFunction()) { 615488b9fd1SDaniil Dudkin if (auto fr{CharacterizeFunctionResult( 616cb263919SPeter Klausler subp.result(), context, seenProcs, emitError)}) { 61777dc203cSPeter Steinfeld result.functionResult = std::move(fr); 61877dc203cSPeter Steinfeld } else { 61977dc203cSPeter Steinfeld return std::nullopt; 62077dc203cSPeter Steinfeld } 62177dc203cSPeter Steinfeld } else { 62277dc203cSPeter Steinfeld result.attrs.set(Procedure::Attr::Subroutine); 62377dc203cSPeter Steinfeld } 62477dc203cSPeter Steinfeld for (const semantics::Symbol *arg : subp.dummyArgs()) { 62577dc203cSPeter Steinfeld if (!arg) { 62673c3530fSpeter klausler if (subp.isFunction()) { 62773c3530fSpeter klausler return std::nullopt; 62873c3530fSpeter klausler } else { 62977dc203cSPeter Steinfeld result.dummyArguments.emplace_back(AlternateReturn{}); 63073c3530fSpeter klausler } 63177dc203cSPeter Steinfeld } else if (auto argCharacteristics{CharacterizeDummyArgument( 63277dc203cSPeter Steinfeld *arg, context, seenProcs)}) { 63377dc203cSPeter Steinfeld result.dummyArguments.emplace_back( 63477dc203cSPeter Steinfeld std::move(argCharacteristics.value())); 63577dc203cSPeter Steinfeld } else { 63677dc203cSPeter Steinfeld return std::nullopt; 63777dc203cSPeter Steinfeld } 63877dc203cSPeter Steinfeld } 639f513bd80SPeter Klausler result.cudaSubprogramAttrs = subp.cudaSubprogramAttrs(); 6400c0b2ea9SPeter Klausler return std::move(result); 64177dc203cSPeter Steinfeld }, 64277dc203cSPeter Steinfeld [&](const semantics::ProcEntityDetails &proc) 64377dc203cSPeter Steinfeld -> std::optional<Procedure> { 64477dc203cSPeter Steinfeld if (symbol.attrs().test(semantics::Attr::INTRINSIC)) { 645f8f70028Speter klausler // Fails when the intrinsic is not a specific intrinsic function 646f8f70028Speter klausler // from F'2018 table 16.2. In order to handle forward references, 647f8f70028Speter klausler // attempts to use impermissible intrinsic procedures as the 648f8f70028Speter klausler // interfaces of procedure pointers are caught and flagged in 649f8f70028Speter klausler // declaration checking in Semantics. 650848cca6cSEmil Kieri auto intrinsic{context.intrinsics().IsSpecificIntrinsicFunction( 651848cca6cSEmil Kieri symbol.name().ToString())}; 652848cca6cSEmil Kieri if (intrinsic && intrinsic->isRestrictedSpecific) { 653848cca6cSEmil Kieri intrinsic.reset(); // Exclude intrinsics from table 16.3. 654848cca6cSEmil Kieri } 655848cca6cSEmil Kieri return intrinsic; 65677dc203cSPeter Steinfeld } 657635656f4SPeter Klausler if (const semantics::Symbol * 658635656f4SPeter Klausler interfaceSymbol{proc.procInterface()}) { 659cb263919SPeter Klausler auto result{CharacterizeProcedure( 660cb263919SPeter Klausler *interfaceSymbol, context, seenProcs, /*emitError=*/false)}; 6610c0b2ea9SPeter Klausler if (result && (IsDummy(symbol) || IsPointer(symbol))) { 6620c0b2ea9SPeter Klausler // Dummy procedures and procedure pointers may not be 6630c0b2ea9SPeter Klausler // ELEMENTAL, but we do accept the use of elemental intrinsic 6640c0b2ea9SPeter Klausler // functions as their interfaces. 6650c0b2ea9SPeter Klausler result->attrs.reset(Procedure::Attr::Elemental); 66695f4ca7fSPeter Klausler } 6670c0b2ea9SPeter Klausler return result; 66877dc203cSPeter Steinfeld } else { 6690c0b2ea9SPeter Klausler Procedure result; 67077dc203cSPeter Steinfeld result.attrs.set(Procedure::Attr::ImplicitInterface); 671635656f4SPeter Klausler const semantics::DeclTypeSpec *type{proc.type()}; 67277dc203cSPeter Steinfeld if (symbol.test(semantics::Symbol::Flag::Subroutine)) { 67377dc203cSPeter Steinfeld // ignore any implicit typing 67477dc203cSPeter Steinfeld result.attrs.set(Procedure::Attr::Subroutine); 675f513bd80SPeter Klausler if (proc.isCUDAKernel()) { 676f513bd80SPeter Klausler result.cudaSubprogramAttrs = 677f513bd80SPeter Klausler common::CUDASubprogramAttrs::Global; 678f513bd80SPeter Klausler } 67977dc203cSPeter Steinfeld } else if (type) { 68077dc203cSPeter Steinfeld if (auto resultType{DynamicType::From(*type)}) { 68177dc203cSPeter Steinfeld result.functionResult = FunctionResult{*resultType}; 68277dc203cSPeter Steinfeld } else { 68377dc203cSPeter Steinfeld return std::nullopt; 68477dc203cSPeter Steinfeld } 68577dc203cSPeter Steinfeld } else if (symbol.test(semantics::Symbol::Flag::Function)) { 68677dc203cSPeter Steinfeld return std::nullopt; 68777dc203cSPeter Steinfeld } 68877dc203cSPeter Steinfeld // The PASS name, if any, is not a characteristic. 6890c0b2ea9SPeter Klausler return std::move(result); 69077dc203cSPeter Steinfeld } 69177dc203cSPeter Steinfeld }, 69277dc203cSPeter Steinfeld [&](const semantics::ProcBindingDetails &binding) { 693cb263919SPeter Klausler if (auto result{CharacterizeProcedure(binding.symbol(), context, 694cb263919SPeter Klausler seenProcs, /*emitError=*/false)}) { 6955e8094baSPeter Klausler if (binding.symbol().attrs().test(semantics::Attr::INTRINSIC)) { 6965e8094baSPeter Klausler result->attrs.reset(Procedure::Attr::Elemental); 6975e8094baSPeter Klausler } 69877dc203cSPeter Steinfeld if (!symbol.attrs().test(semantics::Attr::NOPASS)) { 69977dc203cSPeter Steinfeld auto passName{binding.passName()}; 70077dc203cSPeter Steinfeld for (auto &dummy : result->dummyArguments) { 70177dc203cSPeter Steinfeld if (!passName || dummy.name.c_str() == *passName) { 70277dc203cSPeter Steinfeld dummy.pass = true; 7035e8094baSPeter Klausler break; 70477dc203cSPeter Steinfeld } 70577dc203cSPeter Steinfeld } 70677dc203cSPeter Steinfeld } 70777dc203cSPeter Steinfeld return result; 70877dc203cSPeter Steinfeld } else { 70977dc203cSPeter Steinfeld return std::optional<Procedure>{}; 71077dc203cSPeter Steinfeld } 71177dc203cSPeter Steinfeld }, 71277dc203cSPeter Steinfeld [&](const semantics::UseDetails &use) { 713cb263919SPeter Klausler return CharacterizeProcedure( 714cb263919SPeter Klausler use.symbol(), context, seenProcs, /*emitError=*/false); 71577dc203cSPeter Steinfeld }, 716a61835b1SDaniil Dudkin [](const semantics::UseErrorDetails &) { 717a61835b1SDaniil Dudkin // Ambiguous use-association will be handled later during symbol 718a61835b1SDaniil Dudkin // checks, ignore UseErrorDetails here without actual symbol usage. 719a61835b1SDaniil Dudkin return std::optional<Procedure>{}; 720a61835b1SDaniil Dudkin }, 72177dc203cSPeter Steinfeld [&](const semantics::HostAssocDetails &assoc) { 722cb263919SPeter Klausler return CharacterizeProcedure( 723cb263919SPeter Klausler assoc.symbol(), context, seenProcs, /*emitError=*/false); 72477dc203cSPeter Steinfeld }, 72546c49e66SPeter Klausler [&](const semantics::GenericDetails &generic) { 72646c49e66SPeter Klausler if (const semantics::Symbol * specific{generic.specific()}) { 727cb263919SPeter Klausler return CharacterizeProcedure( 728cb263919SPeter Klausler *specific, context, seenProcs, emitError); 72946c49e66SPeter Klausler } else { 73046c49e66SPeter Klausler return std::optional<Procedure>{}; 73146c49e66SPeter Klausler } 73246c49e66SPeter Klausler }, 733a54e8b2cSPeter Klausler [&](const semantics::EntityDetails &x) { 734cb263919SPeter Klausler CheckForNested(symbol); 735562bfe12Speter klausler return std::optional<Procedure>{}; 736562bfe12Speter klausler }, 737562bfe12Speter klausler [&](const semantics::SubprogramNameDetails &) { 738a54e8b2cSPeter Klausler if (const semantics::Symbol * 739a54e8b2cSPeter Klausler ancestor{FindAncestorModuleProcedure(&symbol)}) { 740a54e8b2cSPeter Klausler return CharacterizeProcedure( 741a54e8b2cSPeter Klausler *ancestor, context, seenProcs, emitError); 742a54e8b2cSPeter Klausler } 743cb263919SPeter Klausler CheckForNested(symbol); 744562bfe12Speter klausler return std::optional<Procedure>{}; 745562bfe12Speter klausler }, 746562bfe12Speter klausler [&](const auto &) { 747562bfe12Speter klausler context.messages().Say( 748562bfe12Speter klausler "'%s' is not a procedure"_err_en_US, symbol.name()); 749562bfe12Speter klausler return std::optional<Procedure>{}; 750562bfe12Speter klausler }, 75177dc203cSPeter Steinfeld }, 7520c0b2ea9SPeter Klausler symbol.details())}; 7530c0b2ea9SPeter Klausler if (result && !symbol.has<semantics::ProcBindingDetails>()) { 75409c544e7SjeanPerier CopyAttrs<Procedure, Procedure::Attr>(symbol, *result, 7550c0b2ea9SPeter Klausler { 7560c0b2ea9SPeter Klausler {semantics::Attr::BIND_C, Procedure::Attr::BindC}, 75709c544e7SjeanPerier }); 75809c544e7SjeanPerier CopyAttrs<Procedure, Procedure::Attr>(DEREF(GetMainEntry(&symbol)), *result, 75909c544e7SjeanPerier { 7600c0b2ea9SPeter Klausler {semantics::Attr::ELEMENTAL, Procedure::Attr::Elemental}, 7610c0b2ea9SPeter Klausler }); 7620c0b2ea9SPeter Klausler if (IsPureProcedure(symbol) || // works for ENTRY too 7630c0b2ea9SPeter Klausler (!IsExplicitlyImpureProcedure(symbol) && 7640c0b2ea9SPeter Klausler result->attrs.test(Procedure::Attr::Elemental))) { 7650c0b2ea9SPeter Klausler result->attrs.set(Procedure::Attr::Pure); 7660c0b2ea9SPeter Klausler } 7670c0b2ea9SPeter Klausler } 7680c0b2ea9SPeter Klausler return result; 76977dc203cSPeter Steinfeld } 77077dc203cSPeter Steinfeld 77177dc203cSPeter Steinfeld static std::optional<DummyProcedure> CharacterizeDummyProcedure( 77277dc203cSPeter Steinfeld const semantics::Symbol &symbol, FoldingContext &context, 773174cabedSPeter Klausler semantics::UnorderedSymbolSet seenProcs) { 774cb263919SPeter Klausler if (auto procedure{CharacterizeProcedure( 775cb263919SPeter Klausler symbol, context, seenProcs, /*emitError=*/true)}) { 77664ab3302SCarolineConcatto // Dummy procedures may not be elemental. Elemental dummy procedure 77764ab3302SCarolineConcatto // interfaces are errors when the interface is not intrinsic, and that 77864ab3302SCarolineConcatto // error is caught elsewhere. Elemental intrinsic interfaces are 77964ab3302SCarolineConcatto // made non-elemental. 78064ab3302SCarolineConcatto procedure->attrs.reset(Procedure::Attr::Elemental); 78164ab3302SCarolineConcatto DummyProcedure result{std::move(procedure.value())}; 78264ab3302SCarolineConcatto CopyAttrs<DummyProcedure, DummyProcedure::Attr>(symbol, result, 78364ab3302SCarolineConcatto { 78464ab3302SCarolineConcatto {semantics::Attr::OPTIONAL, DummyProcedure::Attr::Optional}, 78564ab3302SCarolineConcatto {semantics::Attr::POINTER, DummyProcedure::Attr::Pointer}, 78664ab3302SCarolineConcatto }); 78764ab3302SCarolineConcatto result.intent = GetIntent(symbol.attrs()); 78864ab3302SCarolineConcatto return result; 78964ab3302SCarolineConcatto } else { 79064ab3302SCarolineConcatto return std::nullopt; 79164ab3302SCarolineConcatto } 79264ab3302SCarolineConcatto } 79364ab3302SCarolineConcatto 7948670e499SCaroline Concatto llvm::raw_ostream &DummyProcedure::Dump(llvm::raw_ostream &o) const { 79564ab3302SCarolineConcatto attrs.Dump(o, EnumToString); 79664ab3302SCarolineConcatto if (intent != common::Intent::Default) { 79764ab3302SCarolineConcatto o << "INTENT(" << common::EnumToString(intent) << ')'; 79864ab3302SCarolineConcatto } 79964ab3302SCarolineConcatto procedure.value().Dump(o); 80064ab3302SCarolineConcatto return o; 80164ab3302SCarolineConcatto } 80264ab3302SCarolineConcatto 8038670e499SCaroline Concatto llvm::raw_ostream &AlternateReturn::Dump(llvm::raw_ostream &o) const { 8048670e499SCaroline Concatto return o << '*'; 8058670e499SCaroline Concatto } 80664ab3302SCarolineConcatto 80764ab3302SCarolineConcatto DummyArgument::~DummyArgument() {} 80864ab3302SCarolineConcatto 80964ab3302SCarolineConcatto bool DummyArgument::operator==(const DummyArgument &that) const { 81064ab3302SCarolineConcatto return u == that.u; // name and passed-object usage are not characteristics 81164ab3302SCarolineConcatto } 81264ab3302SCarolineConcatto 813e86591b3SPeter Klausler bool DummyArgument::IsCompatibleWith(const DummyArgument &actual, 814e86591b3SPeter Klausler std::string *whyNot, std::optional<std::string> *warning) const { 8153bfe9074SPeter Klausler if (const auto *ifaceData{std::get_if<DummyDataObject>(&u)}) { 81662d874f2SPeter Klausler if (const auto *actualData{std::get_if<DummyDataObject>(&actual.u)}) { 817e86591b3SPeter Klausler return ifaceData->IsCompatibleWith(*actualData, whyNot, warning); 8183bfe9074SPeter Klausler } 81962d874f2SPeter Klausler if (whyNot) { 82062d874f2SPeter Klausler *whyNot = "one dummy argument is an object, the other is not"; 82162d874f2SPeter Klausler } 82262d874f2SPeter Klausler } else if (const auto *ifaceProc{std::get_if<DummyProcedure>(&u)}) { 82362d874f2SPeter Klausler if (const auto *actualProc{std::get_if<DummyProcedure>(&actual.u)}) { 82462d874f2SPeter Klausler return ifaceProc->IsCompatibleWith(*actualProc, whyNot); 82562d874f2SPeter Klausler } 82662d874f2SPeter Klausler if (whyNot) { 82762d874f2SPeter Klausler *whyNot = "one dummy argument is a procedure, the other is not"; 82862d874f2SPeter Klausler } 82962d874f2SPeter Klausler } else { 83062d874f2SPeter Klausler CHECK(std::holds_alternative<AlternateReturn>(u)); 83162d874f2SPeter Klausler if (std::holds_alternative<AlternateReturn>(actual.u)) { 83262d874f2SPeter Klausler return true; 83362d874f2SPeter Klausler } 83462d874f2SPeter Klausler if (whyNot) { 83562d874f2SPeter Klausler *whyNot = "one dummy argument is an alternate return, the other is not"; 83662d874f2SPeter Klausler } 83762d874f2SPeter Klausler } 83862d874f2SPeter Klausler return false; 8393bfe9074SPeter Klausler } 8403bfe9074SPeter Klausler 84177dc203cSPeter Steinfeld static std::optional<DummyArgument> CharacterizeDummyArgument( 84277dc203cSPeter Steinfeld const semantics::Symbol &symbol, FoldingContext &context, 843174cabedSPeter Klausler semantics::UnorderedSymbolSet seenProcs) { 84464ab3302SCarolineConcatto auto name{symbol.name().ToString()}; 84573c3530fSpeter klausler if (symbol.has<semantics::ObjectEntityDetails>() || 84673c3530fSpeter klausler symbol.has<semantics::EntityDetails>()) { 847641ede93Speter klausler if (auto obj{DummyDataObject::Characterize(symbol, context)}) { 84864ab3302SCarolineConcatto return DummyArgument{std::move(name), std::move(obj.value())}; 84964ab3302SCarolineConcatto } 85077dc203cSPeter Steinfeld } else if (auto proc{ 85177dc203cSPeter Steinfeld CharacterizeDummyProcedure(symbol, context, seenProcs)}) { 85264ab3302SCarolineConcatto return DummyArgument{std::move(name), std::move(proc.value())}; 85364ab3302SCarolineConcatto } 85464ab3302SCarolineConcatto return std::nullopt; 85564ab3302SCarolineConcatto } 85664ab3302SCarolineConcatto 85729fd3e2aSPeter Klausler std::optional<DummyArgument> DummyArgument::FromActual(std::string &&name, 85829fd3e2aSPeter Klausler const Expr<SomeType> &expr, FoldingContext &context, 85929fd3e2aSPeter Klausler bool forImplicitInterface) { 860cd03e96fSPeter Klausler return common::visit( 86164ab3302SCarolineConcatto common::visitors{ 86264ab3302SCarolineConcatto [&](const BOZLiteralConstant &) { 8635718a425SPeter Klausler DummyDataObject obj{ 8645718a425SPeter Klausler TypeAndShape{DynamicType::TypelessIntrinsicArgument()}}; 8655718a425SPeter Klausler obj.attrs.set(DummyDataObject::Attr::DeducedFromActual); 8665718a425SPeter Klausler return std::make_optional<DummyArgument>( 8675718a425SPeter Klausler std::move(name), std::move(obj)); 86864ab3302SCarolineConcatto }, 869c7574188SPeter Steinfeld [&](const NullPointer &) { 8705718a425SPeter Klausler DummyDataObject obj{ 8715718a425SPeter Klausler TypeAndShape{DynamicType::TypelessIntrinsicArgument()}}; 8725718a425SPeter Klausler obj.attrs.set(DummyDataObject::Attr::DeducedFromActual); 8735718a425SPeter Klausler return std::make_optional<DummyArgument>( 8745718a425SPeter Klausler std::move(name), std::move(obj)); 875c7574188SPeter Steinfeld }, 87664ab3302SCarolineConcatto [&](const ProcedureDesignator &designator) { 877cb263919SPeter Klausler if (auto proc{Procedure::Characterize( 878cb263919SPeter Klausler designator, context, /*emitError=*/true)}) { 87964ab3302SCarolineConcatto return std::make_optional<DummyArgument>( 88064ab3302SCarolineConcatto std::move(name), DummyProcedure{std::move(*proc)}); 88164ab3302SCarolineConcatto } else { 88264ab3302SCarolineConcatto return std::optional<DummyArgument>{}; 88364ab3302SCarolineConcatto } 88464ab3302SCarolineConcatto }, 88564ab3302SCarolineConcatto [&](const ProcedureRef &call) { 886641ede93Speter klausler if (auto proc{Procedure::Characterize(call, context)}) { 88764ab3302SCarolineConcatto return std::make_optional<DummyArgument>( 88864ab3302SCarolineConcatto std::move(name), DummyProcedure{std::move(*proc)}); 88964ab3302SCarolineConcatto } else { 89064ab3302SCarolineConcatto return std::optional<DummyArgument>{}; 89164ab3302SCarolineConcatto } 89264ab3302SCarolineConcatto }, 89364ab3302SCarolineConcatto [&](const auto &) { 894934b27a9Speter klausler if (auto type{TypeAndShape::Characterize(expr, context)}) { 89529fd3e2aSPeter Klausler if (forImplicitInterface && 89629fd3e2aSPeter Klausler !type->type().IsUnlimitedPolymorphic() && 89729fd3e2aSPeter Klausler type->type().IsPolymorphic()) { 89829fd3e2aSPeter Klausler // Pass the monomorphic declared type to an implicit interface 89929fd3e2aSPeter Klausler type->set_type(DynamicType{ 90029fd3e2aSPeter Klausler type->type().GetDerivedTypeSpec(), /*poly=*/false}); 90129fd3e2aSPeter Klausler } 9025718a425SPeter Klausler DummyDataObject obj{std::move(*type)}; 9035718a425SPeter Klausler obj.attrs.set(DummyDataObject::Attr::DeducedFromActual); 90464ab3302SCarolineConcatto return std::make_optional<DummyArgument>( 9055718a425SPeter Klausler std::move(name), std::move(obj)); 90664ab3302SCarolineConcatto } else { 90764ab3302SCarolineConcatto return std::optional<DummyArgument>{}; 90864ab3302SCarolineConcatto } 90964ab3302SCarolineConcatto }, 91064ab3302SCarolineConcatto }, 91164ab3302SCarolineConcatto expr.u); 91264ab3302SCarolineConcatto } 91364ab3302SCarolineConcatto 91429fd3e2aSPeter Klausler std::optional<DummyArgument> DummyArgument::FromActual(std::string &&name, 91529fd3e2aSPeter Klausler const ActualArgument &arg, FoldingContext &context, 91629fd3e2aSPeter Klausler bool forImplicitInterface) { 917bdbebef8SPeter Klausler if (const auto *expr{arg.UnwrapExpr()}) { 91829fd3e2aSPeter Klausler return FromActual(std::move(name), *expr, context, forImplicitInterface); 919bdbebef8SPeter Klausler } else if (arg.GetAssumedTypeDummy()) { 920bdbebef8SPeter Klausler return std::nullopt; 921bdbebef8SPeter Klausler } else { 922bdbebef8SPeter Klausler return DummyArgument{AlternateReturn{}}; 923bdbebef8SPeter Klausler } 924bdbebef8SPeter Klausler } 925bdbebef8SPeter Klausler 92664ab3302SCarolineConcatto bool DummyArgument::IsOptional() const { 927cd03e96fSPeter Klausler return common::visit( 92864ab3302SCarolineConcatto common::visitors{ 92964ab3302SCarolineConcatto [](const DummyDataObject &data) { 93064ab3302SCarolineConcatto return data.attrs.test(DummyDataObject::Attr::Optional); 93164ab3302SCarolineConcatto }, 93264ab3302SCarolineConcatto [](const DummyProcedure &proc) { 93364ab3302SCarolineConcatto return proc.attrs.test(DummyProcedure::Attr::Optional); 93464ab3302SCarolineConcatto }, 93564ab3302SCarolineConcatto [](const AlternateReturn &) { return false; }, 93664ab3302SCarolineConcatto }, 93764ab3302SCarolineConcatto u); 93864ab3302SCarolineConcatto } 93964ab3302SCarolineConcatto 94064ab3302SCarolineConcatto void DummyArgument::SetOptional(bool value) { 941cd03e96fSPeter Klausler common::visit(common::visitors{ 94264ab3302SCarolineConcatto [value](DummyDataObject &data) { 94364ab3302SCarolineConcatto data.attrs.set(DummyDataObject::Attr::Optional, value); 94464ab3302SCarolineConcatto }, 94564ab3302SCarolineConcatto [value](DummyProcedure &proc) { 94664ab3302SCarolineConcatto proc.attrs.set(DummyProcedure::Attr::Optional, value); 94764ab3302SCarolineConcatto }, 94864ab3302SCarolineConcatto [](AlternateReturn &) { DIE("cannot set optional"); }, 94964ab3302SCarolineConcatto }, 95064ab3302SCarolineConcatto u); 95164ab3302SCarolineConcatto } 95264ab3302SCarolineConcatto 95329d1a494SJean Perier void DummyArgument::SetIntent(common::Intent intent) { 954cd03e96fSPeter Klausler common::visit(common::visitors{ 95529d1a494SJean Perier [intent](DummyDataObject &data) { data.intent = intent; }, 95629d1a494SJean Perier [intent](DummyProcedure &proc) { proc.intent = intent; }, 95729d1a494SJean Perier [](AlternateReturn &) { DIE("cannot set intent"); }, 95829d1a494SJean Perier }, 95929d1a494SJean Perier u); 96029d1a494SJean Perier } 96129d1a494SJean Perier 96229d1a494SJean Perier common::Intent DummyArgument::GetIntent() const { 963cd03e96fSPeter Klausler return common::visit( 964cd03e96fSPeter Klausler common::visitors{ 96529d1a494SJean Perier [](const DummyDataObject &data) { return data.intent; }, 96629d1a494SJean Perier [](const DummyProcedure &proc) { return proc.intent; }, 96729d1a494SJean Perier [](const AlternateReturn &) -> common::Intent { 968bc56620bSPeter Steinfeld DIE("Alternate returns have no intent"); 96929d1a494SJean Perier }, 97029d1a494SJean Perier }, 97129d1a494SJean Perier u); 97229d1a494SJean Perier } 97329d1a494SJean Perier 9746e0a2031SPeter Klausler bool DummyArgument::CanBePassedViaImplicitInterface(std::string *whyNot) const { 97564ab3302SCarolineConcatto if (const auto *object{std::get_if<DummyDataObject>(&u)}) { 9766e0a2031SPeter Klausler return object->CanBePassedViaImplicitInterface(whyNot); 97766fdfff7SPeter Klausler } else if (const auto *proc{std::get_if<DummyProcedure>(&u)}) { 9786e0a2031SPeter Klausler return proc->CanBePassedViaImplicitInterface(whyNot); 97964ab3302SCarolineConcatto } else { 98064ab3302SCarolineConcatto return true; 98164ab3302SCarolineConcatto } 98264ab3302SCarolineConcatto } 98364ab3302SCarolineConcatto 984c7574188SPeter Steinfeld bool DummyArgument::IsTypelessIntrinsicDummy() const { 985c7574188SPeter Steinfeld const auto *argObj{std::get_if<characteristics::DummyDataObject>(&u)}; 986c7574188SPeter Steinfeld return argObj && argObj->type.type().IsTypelessIntrinsicArgument(); 987c7574188SPeter Steinfeld } 988c7574188SPeter Steinfeld 9898670e499SCaroline Concatto llvm::raw_ostream &DummyArgument::Dump(llvm::raw_ostream &o) const { 99064ab3302SCarolineConcatto if (!name.empty()) { 99164ab3302SCarolineConcatto o << name << '='; 99264ab3302SCarolineConcatto } 99364ab3302SCarolineConcatto if (pass) { 99464ab3302SCarolineConcatto o << " PASS"; 99564ab3302SCarolineConcatto } 996cd03e96fSPeter Klausler common::visit([&](const auto &x) { x.Dump(o); }, u); 99764ab3302SCarolineConcatto return o; 99864ab3302SCarolineConcatto } 99964ab3302SCarolineConcatto 100064ab3302SCarolineConcatto FunctionResult::FunctionResult(DynamicType t) : u{TypeAndShape{t}} {} 100164ab3302SCarolineConcatto FunctionResult::FunctionResult(TypeAndShape &&t) : u{std::move(t)} {} 100264ab3302SCarolineConcatto FunctionResult::FunctionResult(Procedure &&p) : u{std::move(p)} {} 100364ab3302SCarolineConcatto FunctionResult::~FunctionResult() {} 100464ab3302SCarolineConcatto 100564ab3302SCarolineConcatto bool FunctionResult::operator==(const FunctionResult &that) const { 1006f513bd80SPeter Klausler return attrs == that.attrs && cudaDataAttr == that.cudaDataAttr && 1007f513bd80SPeter Klausler u == that.u; 100864ab3302SCarolineConcatto } 100964ab3302SCarolineConcatto 1010488b9fd1SDaniil Dudkin static std::optional<FunctionResult> CharacterizeFunctionResult( 1011488b9fd1SDaniil Dudkin const semantics::Symbol &symbol, FoldingContext &context, 1012cb263919SPeter Klausler semantics::UnorderedSymbolSet seenProcs, bool emitError) { 1013f513bd80SPeter Klausler if (const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()}) { 10140c0b2ea9SPeter Klausler if (auto type{TypeAndShape::Characterize( 10150c0b2ea9SPeter Klausler symbol, context, /*invariantOnly=*/false)}) { 101664ab3302SCarolineConcatto FunctionResult result{std::move(*type)}; 101764ab3302SCarolineConcatto CopyAttrs<FunctionResult, FunctionResult::Attr>(symbol, result, 101864ab3302SCarolineConcatto { 101964ab3302SCarolineConcatto {semantics::Attr::ALLOCATABLE, FunctionResult::Attr::Allocatable}, 102064ab3302SCarolineConcatto {semantics::Attr::CONTIGUOUS, FunctionResult::Attr::Contiguous}, 102164ab3302SCarolineConcatto {semantics::Attr::POINTER, FunctionResult::Attr::Pointer}, 102264ab3302SCarolineConcatto }); 1023f513bd80SPeter Klausler result.cudaDataAttr = object->cudaDataAttr(); 102464ab3302SCarolineConcatto return result; 102564ab3302SCarolineConcatto } 1026cb263919SPeter Klausler } else if (auto maybeProc{CharacterizeProcedure( 1027cb263919SPeter Klausler symbol, context, seenProcs, emitError)}) { 102864ab3302SCarolineConcatto FunctionResult result{std::move(*maybeProc)}; 102964ab3302SCarolineConcatto result.attrs.set(FunctionResult::Attr::Pointer); 103064ab3302SCarolineConcatto return result; 103164ab3302SCarolineConcatto } 103264ab3302SCarolineConcatto return std::nullopt; 103364ab3302SCarolineConcatto } 103464ab3302SCarolineConcatto 1035488b9fd1SDaniil Dudkin std::optional<FunctionResult> FunctionResult::Characterize( 1036488b9fd1SDaniil Dudkin const Symbol &symbol, FoldingContext &context) { 1037488b9fd1SDaniil Dudkin semantics::UnorderedSymbolSet seenProcs; 1038cb263919SPeter Klausler return CharacterizeFunctionResult( 1039cb263919SPeter Klausler symbol, context, seenProcs, /*emitError=*/false); 1040488b9fd1SDaniil Dudkin } 1041488b9fd1SDaniil Dudkin 104264ab3302SCarolineConcatto bool FunctionResult::IsAssumedLengthCharacter() const { 104364ab3302SCarolineConcatto if (const auto *ts{std::get_if<TypeAndShape>(&u)}) { 104464ab3302SCarolineConcatto return ts->type().IsAssumedLengthCharacter(); 104564ab3302SCarolineConcatto } else { 104664ab3302SCarolineConcatto return false; 104764ab3302SCarolineConcatto } 104864ab3302SCarolineConcatto } 104964ab3302SCarolineConcatto 10506e0a2031SPeter Klausler bool FunctionResult::CanBeReturnedViaImplicitInterface( 10516e0a2031SPeter Klausler std::string *whyNot) const { 105264ab3302SCarolineConcatto if (attrs.test(Attr::Pointer) || attrs.test(Attr::Allocatable)) { 10536e0a2031SPeter Klausler if (whyNot) { 10546e0a2031SPeter Klausler *whyNot = "the function result is a pointer or allocatable"; 10556e0a2031SPeter Klausler } 105664ab3302SCarolineConcatto return false; // 15.4.2.2(4)(b) 1057f513bd80SPeter Klausler } else if (cudaDataAttr) { 10586e0a2031SPeter Klausler if (whyNot) { 10596e0a2031SPeter Klausler *whyNot = "the function result has CUDA attributes"; 10606e0a2031SPeter Klausler } 1061f513bd80SPeter Klausler return false; 106264ab3302SCarolineConcatto } else if (const auto *typeAndShape{GetTypeAndShape()}) { 106364ab3302SCarolineConcatto if (typeAndShape->Rank() > 0) { 10646e0a2031SPeter Klausler if (whyNot) { 10656e0a2031SPeter Klausler *whyNot = "the function result is an array"; 10666e0a2031SPeter Klausler } 106764ab3302SCarolineConcatto return false; // 15.4.2.2(4)(a) 106864ab3302SCarolineConcatto } else { 106964ab3302SCarolineConcatto const DynamicType &type{typeAndShape->type()}; 107064ab3302SCarolineConcatto switch (type.category()) { 107164ab3302SCarolineConcatto case TypeCategory::Character: 1072ac964175Speter klausler if (type.knownLength()) { 1073ac964175Speter klausler return true; 1074ac964175Speter klausler } else if (const auto *param{type.charLengthParamValue()}) { 107564ab3302SCarolineConcatto if (const auto &expr{param->GetExplicit()}) { 10766e0a2031SPeter Klausler if (IsConstantExpr(*expr)) { // 15.4.2.2(4)(c) 10776e0a2031SPeter Klausler return true; 10786e0a2031SPeter Klausler } else { 10796e0a2031SPeter Klausler if (whyNot) { 10806e0a2031SPeter Klausler *whyNot = "the function result's length is not constant"; 10816e0a2031SPeter Klausler } 10826e0a2031SPeter Klausler return false; 10836e0a2031SPeter Klausler } 1084bd72ed93SJean Perier } else if (param->isAssumed()) { 1085bd72ed93SJean Perier return true; 108664ab3302SCarolineConcatto } 108764ab3302SCarolineConcatto } 10886e0a2031SPeter Klausler if (whyNot) { 10896e0a2031SPeter Klausler *whyNot = "the function result's length is not known to the caller"; 10906e0a2031SPeter Klausler } 109164ab3302SCarolineConcatto return false; 109264ab3302SCarolineConcatto case TypeCategory::Derived: 10936e0a2031SPeter Klausler if (type.IsPolymorphic()) { 10946e0a2031SPeter Klausler if (whyNot) { 10956e0a2031SPeter Klausler *whyNot = "the function result is polymorphic"; 10966e0a2031SPeter Klausler } 10976e0a2031SPeter Klausler return false; 10986e0a2031SPeter Klausler } else { 109964ab3302SCarolineConcatto const auto &spec{type.GetDerivedTypeSpec()}; 110064ab3302SCarolineConcatto for (const auto &pair : spec.parameters()) { 110164ab3302SCarolineConcatto if (const auto &expr{pair.second.GetExplicit()}) { 110264ab3302SCarolineConcatto if (!IsConstantExpr(*expr)) { 11036e0a2031SPeter Klausler if (whyNot) { 11046e0a2031SPeter Klausler *whyNot = "the function result's derived type has a " 11056e0a2031SPeter Klausler "non-constant parameter"; 11066e0a2031SPeter Klausler } 110764ab3302SCarolineConcatto return false; // 15.4.2.2(4)(c) 110864ab3302SCarolineConcatto } 110964ab3302SCarolineConcatto } 111064ab3302SCarolineConcatto } 111164ab3302SCarolineConcatto return true; 111264ab3302SCarolineConcatto } 11131f879005STim Keith default: 11141f879005STim Keith return true; 111564ab3302SCarolineConcatto } 111664ab3302SCarolineConcatto } 111764ab3302SCarolineConcatto } else { 11186e0a2031SPeter Klausler if (whyNot) { 11196e0a2031SPeter Klausler *whyNot = "the function result has unknown type or shape"; 11206e0a2031SPeter Klausler } 11216e0a2031SPeter Klausler return false; // 15.4.2.2(4)(b) - procedure pointer? 112264ab3302SCarolineConcatto } 112364ab3302SCarolineConcatto } 112464ab3302SCarolineConcatto 11250c0b2ea9SPeter Klausler static std::optional<std::string> AreIncompatibleFunctionResultShapes( 11260c0b2ea9SPeter Klausler const Shape &x, const Shape &y) { 112773cf0142SjeanPerier // Function results cannot be assumed-rank, hence the non optional arguments. 1128c1a77839SPeter Klausler int rank{GetRank(x)}; 11290c0b2ea9SPeter Klausler if (int yrank{GetRank(y)}; yrank != rank) { 11300c0b2ea9SPeter Klausler return "rank "s + std::to_string(rank) + " vs " + std::to_string(yrank); 1131c1a77839SPeter Klausler } 1132c1a77839SPeter Klausler for (int j{0}; j < rank; ++j) { 11330c0b2ea9SPeter Klausler if (x[j] && y[j] && !(*x[j] == *y[j])) { 11340c0b2ea9SPeter Klausler return x[j]->AsFortran() + " vs " + y[j]->AsFortran(); 1135c1a77839SPeter Klausler } 1136c1a77839SPeter Klausler } 11370c0b2ea9SPeter Klausler return std::nullopt; 1138c1a77839SPeter Klausler } 1139c1a77839SPeter Klausler 114062d874f2SPeter Klausler bool FunctionResult::IsCompatibleWith( 114162d874f2SPeter Klausler const FunctionResult &actual, std::string *whyNot) const { 11423bfe9074SPeter Klausler Attrs actualAttrs{actual.attrs}; 114362d874f2SPeter Klausler if (!attrs.test(Attr::Contiguous)) { 11443bfe9074SPeter Klausler actualAttrs.reset(Attr::Contiguous); 114562d874f2SPeter Klausler } 11463bfe9074SPeter Klausler if (attrs != actualAttrs) { 114762d874f2SPeter Klausler if (whyNot) { 114862d874f2SPeter Klausler *whyNot = "function results have incompatible attributes"; 114962d874f2SPeter Klausler } 1150f513bd80SPeter Klausler } else if (cudaDataAttr != actual.cudaDataAttr) { 1151f513bd80SPeter Klausler if (whyNot) { 1152f513bd80SPeter Klausler *whyNot = "function results have incompatible CUDA data attributes"; 1153f513bd80SPeter Klausler } 11543bfe9074SPeter Klausler } else if (const auto *ifaceTypeShape{std::get_if<TypeAndShape>(&u)}) { 11553bfe9074SPeter Klausler if (const auto *actualTypeShape{std::get_if<TypeAndShape>(&actual.u)}) { 11560c0b2ea9SPeter Klausler std::optional<std::string> details; 1157948d0b34SPeter Klausler if (ifaceTypeShape->Rank() != actualTypeShape->Rank()) { 115862d874f2SPeter Klausler if (whyNot) { 115962d874f2SPeter Klausler *whyNot = "function results have distinct ranks"; 116062d874f2SPeter Klausler } 1161948d0b34SPeter Klausler } else if (!attrs.test(Attr::Allocatable) && !attrs.test(Attr::Pointer) && 11620c0b2ea9SPeter Klausler (details = AreIncompatibleFunctionResultShapes( 116373cf0142SjeanPerier ifaceTypeShape->shape().value(), 116473cf0142SjeanPerier actualTypeShape->shape().value()))) { 116562d874f2SPeter Klausler if (whyNot) { 11660c0b2ea9SPeter Klausler *whyNot = "function results have distinct extents (" + *details + ')'; 116762d874f2SPeter Klausler } 1168c6b9df0fSPeter Klausler } else if (ifaceTypeShape->type() != actualTypeShape->type()) { 11690c0b2ea9SPeter Klausler if (ifaceTypeShape->type().category() != 1170c6b9df0fSPeter Klausler actualTypeShape->type().category()) { 11710c0b2ea9SPeter Klausler } else if (ifaceTypeShape->type().category() == 11720c0b2ea9SPeter Klausler TypeCategory::Character) { 11730c0b2ea9SPeter Klausler if (ifaceTypeShape->type().kind() == actualTypeShape->type().kind()) { 11740c0b2ea9SPeter Klausler if (IsAssumedLengthCharacter() || 11750c0b2ea9SPeter Klausler actual.IsAssumedLengthCharacter()) { 11760c0b2ea9SPeter Klausler return true; 11770c0b2ea9SPeter Klausler } else { 117811529d5bSPeter Klausler auto len{ToInt64(ifaceTypeShape->LEN())}; 117911529d5bSPeter Klausler auto actualLen{ToInt64(actualTypeShape->LEN())}; 118011529d5bSPeter Klausler if (len.has_value() != actualLen.has_value()) { 118111529d5bSPeter Klausler if (whyNot) { 118211529d5bSPeter Klausler *whyNot = "constant-length vs non-constant-length character " 118311529d5bSPeter Klausler "results"; 118411529d5bSPeter Klausler } 118511529d5bSPeter Klausler } else if (len && *len != *actualLen) { 118611529d5bSPeter Klausler if (whyNot) { 118711529d5bSPeter Klausler *whyNot = "character results with distinct lengths"; 118811529d5bSPeter Klausler } 118911529d5bSPeter Klausler } else { 11900c0b2ea9SPeter Klausler const auto *ifaceLenParam{ 11910c0b2ea9SPeter Klausler ifaceTypeShape->type().charLengthParamValue()}; 11920c0b2ea9SPeter Klausler const auto *actualLenParam{ 11930c0b2ea9SPeter Klausler actualTypeShape->type().charLengthParamValue()}; 11940c0b2ea9SPeter Klausler if (ifaceLenParam && actualLenParam && 119511529d5bSPeter Klausler ifaceLenParam->isExplicit() != 119611529d5bSPeter Klausler actualLenParam->isExplicit()) { 119711529d5bSPeter Klausler if (whyNot) { 119811529d5bSPeter Klausler *whyNot = 119911529d5bSPeter Klausler "explicit-length vs deferred-length character results"; 120011529d5bSPeter Klausler } 120111529d5bSPeter Klausler } else { 1202c6b9df0fSPeter Klausler return true; 1203c6b9df0fSPeter Klausler } 1204c6b9df0fSPeter Klausler } 12050c0b2ea9SPeter Klausler } 120611529d5bSPeter Klausler } 12070c0b2ea9SPeter Klausler } else if (ifaceTypeShape->type().category() == TypeCategory::Derived) { 1208c6b9df0fSPeter Klausler if (ifaceTypeShape->type().IsPolymorphic() == 1209c6b9df0fSPeter Klausler actualTypeShape->type().IsPolymorphic() && 1210c6b9df0fSPeter Klausler !ifaceTypeShape->type().IsUnlimitedPolymorphic() && 1211c6b9df0fSPeter Klausler !actualTypeShape->type().IsUnlimitedPolymorphic() && 1212c6b9df0fSPeter Klausler AreSameDerivedType(ifaceTypeShape->type().GetDerivedTypeSpec(), 1213c6b9df0fSPeter Klausler actualTypeShape->type().GetDerivedTypeSpec())) { 1214c6b9df0fSPeter Klausler return true; 1215c6b9df0fSPeter Klausler } 1216c6b9df0fSPeter Klausler } 121762d874f2SPeter Klausler if (whyNot) { 1218c6b9df0fSPeter Klausler *whyNot = "function results have distinct types: "s + 121962d874f2SPeter Klausler ifaceTypeShape->type().AsFortran() + " vs "s + 122062d874f2SPeter Klausler actualTypeShape->type().AsFortran(); 12213bfe9074SPeter Klausler } 12223bfe9074SPeter Klausler } else { 122362d874f2SPeter Klausler return true; 122462d874f2SPeter Klausler } 122562d874f2SPeter Klausler } else { 122662d874f2SPeter Klausler if (whyNot) { 122762d874f2SPeter Klausler *whyNot = "function result type and shape are not known"; 122862d874f2SPeter Klausler } 12293bfe9074SPeter Klausler } 12303bfe9074SPeter Klausler } else { 12313bfe9074SPeter Klausler const auto *ifaceProc{std::get_if<CopyableIndirection<Procedure>>(&u)}; 123262d874f2SPeter Klausler CHECK(ifaceProc != nullptr); 12333bfe9074SPeter Klausler if (const auto *actualProc{ 12343bfe9074SPeter Klausler std::get_if<CopyableIndirection<Procedure>>(&actual.u)}) { 12351c530b3dSPeter Klausler if (ifaceProc->value().IsCompatibleWith(actualProc->value(), 12361c530b3dSPeter Klausler /*ignoreImplicitVsExplicit=*/false, whyNot)) { 123762d874f2SPeter Klausler return true; 123862d874f2SPeter Klausler } 123962d874f2SPeter Klausler if (whyNot) { 124062d874f2SPeter Klausler *whyNot = 124162d874f2SPeter Klausler "function results are incompatible procedure pointers: "s + *whyNot; 124262d874f2SPeter Klausler } 12433bfe9074SPeter Klausler } else { 124462d874f2SPeter Klausler if (whyNot) { 124562d874f2SPeter Klausler *whyNot = 124662d874f2SPeter Klausler "one function result is a procedure pointer, the other is not"; 124762d874f2SPeter Klausler } 124862d874f2SPeter Klausler } 124962d874f2SPeter Klausler } 12503bfe9074SPeter Klausler return false; 12513bfe9074SPeter Klausler } 12523bfe9074SPeter Klausler 12538670e499SCaroline Concatto llvm::raw_ostream &FunctionResult::Dump(llvm::raw_ostream &o) const { 125464ab3302SCarolineConcatto attrs.Dump(o, EnumToString); 1255cd03e96fSPeter Klausler common::visit(common::visitors{ 125664ab3302SCarolineConcatto [&](const TypeAndShape &ts) { ts.Dump(o); }, 125764ab3302SCarolineConcatto [&](const CopyableIndirection<Procedure> &p) { 125864ab3302SCarolineConcatto p.value().Dump(o << " procedure(") << ')'; 125964ab3302SCarolineConcatto }, 126064ab3302SCarolineConcatto }, 126164ab3302SCarolineConcatto u); 1262f513bd80SPeter Klausler if (cudaDataAttr) { 1263f513bd80SPeter Klausler o << " cudaDataAttr: " << common::EnumToString(*cudaDataAttr); 1264f513bd80SPeter Klausler } 126564ab3302SCarolineConcatto return o; 126664ab3302SCarolineConcatto } 126764ab3302SCarolineConcatto 126864ab3302SCarolineConcatto Procedure::Procedure(FunctionResult &&fr, DummyArguments &&args, Attrs a) 12691f879005STim Keith : functionResult{std::move(fr)}, dummyArguments{std::move(args)}, attrs{a} { 12701f879005STim Keith } 127164ab3302SCarolineConcatto Procedure::Procedure(DummyArguments &&args, Attrs a) 127264ab3302SCarolineConcatto : dummyArguments{std::move(args)}, attrs{a} {} 127364ab3302SCarolineConcatto Procedure::~Procedure() {} 127464ab3302SCarolineConcatto 127564ab3302SCarolineConcatto bool Procedure::operator==(const Procedure &that) const { 127664ab3302SCarolineConcatto return attrs == that.attrs && functionResult == that.functionResult && 1277f513bd80SPeter Klausler dummyArguments == that.dummyArguments && 1278f513bd80SPeter Klausler cudaSubprogramAttrs == that.cudaSubprogramAttrs; 127964ab3302SCarolineConcatto } 128064ab3302SCarolineConcatto 12811c530b3dSPeter Klausler bool Procedure::IsCompatibleWith(const Procedure &actual, 12821c530b3dSPeter Klausler bool ignoreImplicitVsExplicit, std::string *whyNot, 1283e86591b3SPeter Klausler const SpecificIntrinsic *specificIntrinsic, 1284e86591b3SPeter Klausler std::optional<std::string> *warning) const { 12853bfe9074SPeter Klausler // 15.5.2.9(1): if dummy is not pure, actual need not be. 128662d874f2SPeter Klausler // Ditto with elemental. 12873bfe9074SPeter Klausler Attrs actualAttrs{actual.attrs}; 12883bfe9074SPeter Klausler if (!attrs.test(Attr::Pure)) { 12893bfe9074SPeter Klausler actualAttrs.reset(Attr::Pure); 12903bfe9074SPeter Klausler } 129195f4ca7fSPeter Klausler if (!attrs.test(Attr::Elemental) && specificIntrinsic) { 129262d874f2SPeter Klausler actualAttrs.reset(Attr::Elemental); 129362d874f2SPeter Klausler } 1294b09c8905SPeter Klausler Attrs differences{attrs ^ actualAttrs}; 1295b09c8905SPeter Klausler differences.reset(Attr::Subroutine); // dealt with specifically later 12961c530b3dSPeter Klausler if (ignoreImplicitVsExplicit) { 12971c530b3dSPeter Klausler differences.reset(Attr::ImplicitInterface); 12981c530b3dSPeter Klausler } 1299b09c8905SPeter Klausler if (!differences.empty()) { 130062d874f2SPeter Klausler if (whyNot) { 1301b09c8905SPeter Klausler auto sep{": "s}; 130262d874f2SPeter Klausler *whyNot = "incompatible procedure attributes"; 1303b09c8905SPeter Klausler differences.IterateOverMembers([&](Attr x) { 1304bcba39a5SPeter Klausler *whyNot += sep + std::string{EnumToString(x)}; 1305b09c8905SPeter Klausler sep = ", "; 1306b09c8905SPeter Klausler }); 130762d874f2SPeter Klausler } 130862d874f2SPeter Klausler } else if ((IsFunction() && actual.IsSubroutine()) || 130962d874f2SPeter Klausler (IsSubroutine() && actual.IsFunction())) { 131062d874f2SPeter Klausler if (whyNot) { 131162d874f2SPeter Klausler *whyNot = 131262d874f2SPeter Klausler "incompatible procedures: one is a function, the other a subroutine"; 131362d874f2SPeter Klausler } 131462d874f2SPeter Klausler } else if (functionResult && actual.functionResult && 131562d874f2SPeter Klausler !functionResult->IsCompatibleWith(*actual.functionResult, whyNot)) { 1316f513bd80SPeter Klausler } else if (cudaSubprogramAttrs != actual.cudaSubprogramAttrs) { 1317f513bd80SPeter Klausler if (whyNot) { 1318f513bd80SPeter Klausler *whyNot = "incompatible CUDA subprogram attributes"; 1319f513bd80SPeter Klausler } 13203bfe9074SPeter Klausler } else if (dummyArguments.size() != actual.dummyArguments.size()) { 132162d874f2SPeter Klausler if (whyNot) { 132262d874f2SPeter Klausler *whyNot = "distinct numbers of dummy arguments"; 132362d874f2SPeter Klausler } 13243bfe9074SPeter Klausler } else { 13253bfe9074SPeter Klausler for (std::size_t j{0}; j < dummyArguments.size(); ++j) { 1326036701a1SPeter Klausler // Subtlety: the dummy/actual distinction must be reversed for this 1327036701a1SPeter Klausler // compatibility test in order to correctly check extended vs. 1328036701a1SPeter Klausler // base types. Example: 1329036701a1SPeter Klausler // subroutine s1(base); subroutine s2(extended) 1330036701a1SPeter Klausler // procedure(s1), pointer :: p 1331036701a1SPeter Klausler // p => s2 ! an error, s2 is more restricted, can't handle "base" 1332e86591b3SPeter Klausler std::optional<std::string> gotWarning; 1333036701a1SPeter Klausler if (!actual.dummyArguments[j].IsCompatibleWith( 1334e86591b3SPeter Klausler dummyArguments[j], whyNot, warning ? &gotWarning : nullptr)) { 133562d874f2SPeter Klausler if (whyNot) { 133662d874f2SPeter Klausler *whyNot = "incompatible dummy argument #"s + std::to_string(j + 1) + 133762d874f2SPeter Klausler ": "s + *whyNot; 133862d874f2SPeter Klausler } 13393bfe9074SPeter Klausler return false; 1340e86591b3SPeter Klausler } else if (warning && !*warning && gotWarning) { 1341e86591b3SPeter Klausler *warning = "possibly incompatible dummy argument #"s + 1342e86591b3SPeter Klausler std::to_string(j + 1) + ": "s + std::move(*gotWarning); 13433bfe9074SPeter Klausler } 13443bfe9074SPeter Klausler } 13453bfe9074SPeter Klausler return true; 13463bfe9074SPeter Klausler } 134762d874f2SPeter Klausler return false; 13483bfe9074SPeter Klausler } 13493bfe9074SPeter Klausler 13506d2b23c4SPeter Klausler std::optional<int> Procedure::FindPassIndex( 13516d2b23c4SPeter Klausler std::optional<parser::CharBlock> name) const { 135264ab3302SCarolineConcatto int argCount{static_cast<int>(dummyArguments.size())}; 135364ab3302SCarolineConcatto if (name) { 13546d2b23c4SPeter Klausler for (int index{0}; index < argCount; ++index) { 13556d2b23c4SPeter Klausler if (*name == dummyArguments[index].name.c_str()) { 135664ab3302SCarolineConcatto return index; 135764ab3302SCarolineConcatto } 13586d2b23c4SPeter Klausler } 13596d2b23c4SPeter Klausler return std::nullopt; 13606d2b23c4SPeter Klausler } else if (argCount > 0) { 13616d2b23c4SPeter Klausler return 0; 13626d2b23c4SPeter Klausler } else { 13636d2b23c4SPeter Klausler return std::nullopt; 13646d2b23c4SPeter Klausler } 13656d2b23c4SPeter Klausler } 136664ab3302SCarolineConcatto 136764ab3302SCarolineConcatto bool Procedure::CanOverride( 136864ab3302SCarolineConcatto const Procedure &that, std::optional<int> passIndex) const { 136964ab3302SCarolineConcatto // A pure procedure may override an impure one (7.5.7.3(2)) 137064ab3302SCarolineConcatto if ((that.attrs.test(Attr::Pure) && !attrs.test(Attr::Pure)) || 137164ab3302SCarolineConcatto that.attrs.test(Attr::Elemental) != attrs.test(Attr::Elemental) || 137264ab3302SCarolineConcatto functionResult != that.functionResult) { 137364ab3302SCarolineConcatto return false; 137464ab3302SCarolineConcatto } 137564ab3302SCarolineConcatto int argCount{static_cast<int>(dummyArguments.size())}; 137664ab3302SCarolineConcatto if (argCount != static_cast<int>(that.dummyArguments.size())) { 137764ab3302SCarolineConcatto return false; 137864ab3302SCarolineConcatto } 137964ab3302SCarolineConcatto for (int j{0}; j < argCount; ++j) { 1380a3c6a7d5SPeter Klausler if (passIndex && j == *passIndex) { 1381a3c6a7d5SPeter Klausler if (!that.dummyArguments[j].IsCompatibleWith(dummyArguments[j])) { 1382a3c6a7d5SPeter Klausler return false; 1383a3c6a7d5SPeter Klausler } 1384a3c6a7d5SPeter Klausler } else if (dummyArguments[j] != that.dummyArguments[j]) { 138564ab3302SCarolineConcatto return false; 138664ab3302SCarolineConcatto } 138764ab3302SCarolineConcatto } 138864ab3302SCarolineConcatto return true; 138964ab3302SCarolineConcatto } 139064ab3302SCarolineConcatto 139164ab3302SCarolineConcatto std::optional<Procedure> Procedure::Characterize( 1392cb263919SPeter Klausler const semantics::Symbol &symbol, FoldingContext &context) { 13930d8331c0Speter klausler semantics::UnorderedSymbolSet seenProcs; 1394cb263919SPeter Klausler return CharacterizeProcedure(symbol, context, seenProcs, /*emitError=*/true); 139564ab3302SCarolineConcatto } 139664ab3302SCarolineConcatto 139764ab3302SCarolineConcatto std::optional<Procedure> Procedure::Characterize( 1398cb263919SPeter Klausler const ProcedureDesignator &proc, FoldingContext &context, bool emitError) { 139964ab3302SCarolineConcatto if (const auto *symbol{proc.GetSymbol()}) { 1400cb263919SPeter Klausler semantics::UnorderedSymbolSet seenProcs; 1401cb263919SPeter Klausler return CharacterizeProcedure(*symbol, context, seenProcs, emitError); 140264ab3302SCarolineConcatto } else if (const auto *intrinsic{proc.GetSpecificIntrinsic()}) { 140364ab3302SCarolineConcatto return intrinsic->characteristics.value(); 1404cb263919SPeter Klausler } else { 140564ab3302SCarolineConcatto return std::nullopt; 140664ab3302SCarolineConcatto } 1407cb263919SPeter Klausler } 140864ab3302SCarolineConcatto 140964ab3302SCarolineConcatto std::optional<Procedure> Procedure::Characterize( 1410641ede93Speter klausler const ProcedureRef &ref, FoldingContext &context) { 1411cb263919SPeter Klausler if (auto callee{Characterize(ref.proc(), context, /*emitError=*/true)}) { 141264ab3302SCarolineConcatto if (callee->functionResult) { 141364ab3302SCarolineConcatto if (const Procedure * 141464ab3302SCarolineConcatto proc{callee->functionResult->IsProcedurePointer()}) { 141564ab3302SCarolineConcatto return {*proc}; 141664ab3302SCarolineConcatto } 141764ab3302SCarolineConcatto } 141864ab3302SCarolineConcatto } 141964ab3302SCarolineConcatto return std::nullopt; 142064ab3302SCarolineConcatto } 142164ab3302SCarolineConcatto 1422f025e411SPeter Klausler std::optional<Procedure> Procedure::Characterize( 1423f025e411SPeter Klausler const Expr<SomeType> &expr, FoldingContext &context) { 1424f025e411SPeter Klausler if (const auto *procRef{UnwrapProcedureRef(expr)}) { 1425f025e411SPeter Klausler return Characterize(*procRef, context); 1426f025e411SPeter Klausler } else if (const auto *procDesignator{ 1427f025e411SPeter Klausler std::get_if<ProcedureDesignator>(&expr.u)}) { 1428cb263919SPeter Klausler return Characterize(*procDesignator, context, /*emitError=*/true); 1429f025e411SPeter Klausler } else if (const Symbol * symbol{UnwrapWholeSymbolOrComponentDataRef(expr)}) { 1430f025e411SPeter Klausler return Characterize(*symbol, context); 1431f025e411SPeter Klausler } else { 1432f025e411SPeter Klausler context.messages().Say( 1433f025e411SPeter Klausler "Expression '%s' is not a procedure"_err_en_US, expr.AsFortran()); 1434f025e411SPeter Klausler return std::nullopt; 1435f025e411SPeter Klausler } 1436f025e411SPeter Klausler } 1437f025e411SPeter Klausler 1438bdbebef8SPeter Klausler std::optional<Procedure> Procedure::FromActuals(const ProcedureDesignator &proc, 1439bdbebef8SPeter Klausler const ActualArguments &args, FoldingContext &context) { 1440cb263919SPeter Klausler auto callee{Characterize(proc, context, /*emitError=*/true)}; 1441bdbebef8SPeter Klausler if (callee) { 1442bdbebef8SPeter Klausler if (callee->dummyArguments.empty() && 1443bdbebef8SPeter Klausler callee->attrs.test(Procedure::Attr::ImplicitInterface)) { 1444bdbebef8SPeter Klausler int j{0}; 1445bdbebef8SPeter Klausler for (const auto &arg : args) { 1446bdbebef8SPeter Klausler ++j; 1447bdbebef8SPeter Klausler if (arg) { 144829fd3e2aSPeter Klausler if (auto dummy{DummyArgument::FromActual("x"s + std::to_string(j), 144929fd3e2aSPeter Klausler *arg, context, 145029fd3e2aSPeter Klausler /*forImplicitInterface=*/true)}) { 1451bdbebef8SPeter Klausler callee->dummyArguments.emplace_back(std::move(*dummy)); 1452bdbebef8SPeter Klausler continue; 1453bdbebef8SPeter Klausler } 1454bdbebef8SPeter Klausler } 1455bdbebef8SPeter Klausler callee.reset(); 1456bdbebef8SPeter Klausler break; 1457bdbebef8SPeter Klausler } 1458bdbebef8SPeter Klausler } 1459bdbebef8SPeter Klausler } 1460bdbebef8SPeter Klausler return callee; 1461bdbebef8SPeter Klausler } 1462bdbebef8SPeter Klausler 14636e0a2031SPeter Klausler bool Procedure::CanBeCalledViaImplicitInterface(std::string *whyNot) const { 14646e0a2031SPeter Klausler if (attrs.test(Attr::Elemental)) { 14656e0a2031SPeter Klausler if (whyNot) { 14666e0a2031SPeter Klausler *whyNot = "the procedure is elemental"; 14676e0a2031SPeter Klausler } 14686e0a2031SPeter Klausler return false; // 15.4.2.2(5,6) 14696e0a2031SPeter Klausler } else if (attrs.test(Attr::BindC)) { 14706e0a2031SPeter Klausler if (whyNot) { 14716e0a2031SPeter Klausler *whyNot = "the procedure is BIND(C)"; 14726e0a2031SPeter Klausler } 147364ab3302SCarolineConcatto return false; // 15.4.2.2(5,6) 1474f513bd80SPeter Klausler } else if (cudaSubprogramAttrs && 1475f513bd80SPeter Klausler *cudaSubprogramAttrs != common::CUDASubprogramAttrs::Host && 1476f513bd80SPeter Klausler *cudaSubprogramAttrs != common::CUDASubprogramAttrs::Global) { 14776e0a2031SPeter Klausler if (whyNot) { 14786e0a2031SPeter Klausler *whyNot = "the procedure is CUDA but neither HOST nor GLOBAL"; 14796e0a2031SPeter Klausler } 1480f513bd80SPeter Klausler return false; 148164ab3302SCarolineConcatto } else if (IsFunction() && 14826e0a2031SPeter Klausler !functionResult->CanBeReturnedViaImplicitInterface(whyNot)) { 148364ab3302SCarolineConcatto return false; 148464ab3302SCarolineConcatto } else { 148564ab3302SCarolineConcatto for (const DummyArgument &arg : dummyArguments) { 14866e0a2031SPeter Klausler if (!arg.CanBePassedViaImplicitInterface(whyNot)) { 148764ab3302SCarolineConcatto return false; 148864ab3302SCarolineConcatto } 148964ab3302SCarolineConcatto } 149064ab3302SCarolineConcatto return true; 149164ab3302SCarolineConcatto } 149264ab3302SCarolineConcatto } 149364ab3302SCarolineConcatto 14948670e499SCaroline Concatto llvm::raw_ostream &Procedure::Dump(llvm::raw_ostream &o) const { 149564ab3302SCarolineConcatto attrs.Dump(o, EnumToString); 149664ab3302SCarolineConcatto if (functionResult) { 149764ab3302SCarolineConcatto functionResult->Dump(o << "TYPE(") << ") FUNCTION"; 149862d874f2SPeter Klausler } else if (attrs.test(Attr::Subroutine)) { 149964ab3302SCarolineConcatto o << "SUBROUTINE"; 150062d874f2SPeter Klausler } else { 150162d874f2SPeter Klausler o << "EXTERNAL"; 150264ab3302SCarolineConcatto } 150364ab3302SCarolineConcatto char sep{'('}; 150464ab3302SCarolineConcatto for (const auto &dummy : dummyArguments) { 150564ab3302SCarolineConcatto dummy.Dump(o << sep); 150664ab3302SCarolineConcatto sep = ','; 150764ab3302SCarolineConcatto } 1508f513bd80SPeter Klausler o << (sep == '(' ? "()" : ")"); 1509f513bd80SPeter Klausler if (cudaSubprogramAttrs) { 1510f513bd80SPeter Klausler o << " cudaSubprogramAttrs: " << common::EnumToString(*cudaSubprogramAttrs); 1511f513bd80SPeter Klausler } 1512f513bd80SPeter Klausler return o; 151364ab3302SCarolineConcatto } 151464ab3302SCarolineConcatto 151564ab3302SCarolineConcatto // Utility class to determine if Procedures, etc. are distinguishable 151664ab3302SCarolineConcatto class DistinguishUtils { 151764ab3302SCarolineConcatto public: 1518c4ba1108Speter klausler explicit DistinguishUtils(const common::LanguageFeatureControl &features) 1519c4ba1108Speter klausler : features_{features} {} 1520c4ba1108Speter klausler 152164ab3302SCarolineConcatto // Are these procedures distinguishable for a generic name? 15223d115700SPeter Klausler std::optional<bool> Distinguishable( 15233d115700SPeter Klausler const Procedure &, const Procedure &) const; 152464ab3302SCarolineConcatto // Are these procedures distinguishable for a generic operator or assignment? 15253d115700SPeter Klausler std::optional<bool> DistinguishableOpOrAssign( 15263d115700SPeter Klausler const Procedure &, const Procedure &) const; 152764ab3302SCarolineConcatto 152864ab3302SCarolineConcatto private: 152964ab3302SCarolineConcatto struct CountDummyProcedures { 153064ab3302SCarolineConcatto CountDummyProcedures(const DummyArguments &args) { 153164ab3302SCarolineConcatto for (const DummyArgument &arg : args) { 153264ab3302SCarolineConcatto if (std::holds_alternative<DummyProcedure>(arg.u)) { 153364ab3302SCarolineConcatto total += 1; 153464ab3302SCarolineConcatto notOptional += !arg.IsOptional(); 153564ab3302SCarolineConcatto } 153664ab3302SCarolineConcatto } 153764ab3302SCarolineConcatto } 153864ab3302SCarolineConcatto int total{0}; 153964ab3302SCarolineConcatto int notOptional{0}; 154064ab3302SCarolineConcatto }; 154164ab3302SCarolineConcatto 15423d115700SPeter Klausler bool AnyOptionalData(const DummyArguments &) const; 15433d115700SPeter Klausler bool AnyUnlimitedPolymorphicData(const DummyArguments &) const; 1544c4ba1108Speter klausler bool Rule3Distinguishable(const Procedure &, const Procedure &) const; 1545c4ba1108Speter klausler const DummyArgument *Rule1DistinguishingArg( 1546c4ba1108Speter klausler const DummyArguments &, const DummyArguments &) const; 1547c4ba1108Speter klausler int FindFirstToDistinguishByPosition( 1548c4ba1108Speter klausler const DummyArguments &, const DummyArguments &) const; 1549c4ba1108Speter klausler int FindLastToDistinguishByName( 1550c4ba1108Speter klausler const DummyArguments &, const DummyArguments &) const; 1551c4ba1108Speter klausler int CountCompatibleWith(const DummyArgument &, const DummyArguments &) const; 1552c4ba1108Speter klausler int CountNotDistinguishableFrom( 1553c4ba1108Speter klausler const DummyArgument &, const DummyArguments &) const; 1554c4ba1108Speter klausler bool Distinguishable(const DummyArgument &, const DummyArgument &) const; 1555c4ba1108Speter klausler bool Distinguishable(const DummyDataObject &, const DummyDataObject &) const; 1556c4ba1108Speter klausler bool Distinguishable(const DummyProcedure &, const DummyProcedure &) const; 1557c4ba1108Speter klausler bool Distinguishable(const FunctionResult &, const FunctionResult &) const; 1558864cb2aaSPeter Klausler bool Distinguishable( 1559864cb2aaSPeter Klausler const TypeAndShape &, const TypeAndShape &, common::IgnoreTKRSet) const; 1560c4ba1108Speter klausler bool IsTkrCompatible(const DummyArgument &, const DummyArgument &) const; 1561864cb2aaSPeter Klausler bool IsTkCompatible(const DummyDataObject &, const DummyDataObject &) const; 1562c4ba1108Speter klausler const DummyArgument *GetAtEffectivePosition( 1563c4ba1108Speter klausler const DummyArguments &, int) const; 1564c4ba1108Speter klausler const DummyArgument *GetPassArg(const Procedure &) const; 1565c4ba1108Speter klausler 1566c4ba1108Speter klausler const common::LanguageFeatureControl &features_; 156764ab3302SCarolineConcatto }; 156864ab3302SCarolineConcatto 156964ab3302SCarolineConcatto // Simpler distinguishability rules for operators and assignment 15703d115700SPeter Klausler std::optional<bool> DistinguishUtils::DistinguishableOpOrAssign( 1571c4ba1108Speter klausler const Procedure &proc1, const Procedure &proc2) const { 1572042c964dSPeter Klausler if ((proc1.IsFunction() && proc2.IsSubroutine()) || 1573042c964dSPeter Klausler (proc1.IsSubroutine() && proc2.IsFunction())) { 1574042c964dSPeter Klausler return true; 1575042c964dSPeter Klausler } 157664ab3302SCarolineConcatto auto &args1{proc1.dummyArguments}; 157764ab3302SCarolineConcatto auto &args2{proc2.dummyArguments}; 157864ab3302SCarolineConcatto if (args1.size() != args2.size()) { 157964ab3302SCarolineConcatto return true; // C1511: distinguishable based on number of arguments 158064ab3302SCarolineConcatto } 158164ab3302SCarolineConcatto for (std::size_t i{0}; i < args1.size(); ++i) { 158264ab3302SCarolineConcatto if (Distinguishable(args1[i], args2[i])) { 158364ab3302SCarolineConcatto return true; // C1511, C1512: distinguishable based on this arg 158464ab3302SCarolineConcatto } 158564ab3302SCarolineConcatto } 158664ab3302SCarolineConcatto return false; 158764ab3302SCarolineConcatto } 158864ab3302SCarolineConcatto 15893d115700SPeter Klausler std::optional<bool> DistinguishUtils::Distinguishable( 1590c4ba1108Speter klausler const Procedure &proc1, const Procedure &proc2) const { 1591042c964dSPeter Klausler if ((proc1.IsFunction() && proc2.IsSubroutine()) || 1592042c964dSPeter Klausler (proc1.IsSubroutine() && proc2.IsFunction())) { 1593042c964dSPeter Klausler return true; 1594042c964dSPeter Klausler } 159564ab3302SCarolineConcatto auto &args1{proc1.dummyArguments}; 159664ab3302SCarolineConcatto auto &args2{proc2.dummyArguments}; 159764ab3302SCarolineConcatto auto count1{CountDummyProcedures(args1)}; 159864ab3302SCarolineConcatto auto count2{CountDummyProcedures(args2)}; 159964ab3302SCarolineConcatto if (count1.notOptional > count2.total || count2.notOptional > count1.total) { 160064ab3302SCarolineConcatto return true; // distinguishable based on C1514 rule 2 160164ab3302SCarolineConcatto } 160264ab3302SCarolineConcatto if (Rule3Distinguishable(proc1, proc2)) { 160364ab3302SCarolineConcatto return true; // distinguishable based on C1514 rule 3 160464ab3302SCarolineConcatto } 160564ab3302SCarolineConcatto if (Rule1DistinguishingArg(args1, args2)) { 160664ab3302SCarolineConcatto return true; // distinguishable based on C1514 rule 1 160764ab3302SCarolineConcatto } 160864ab3302SCarolineConcatto int pos1{FindFirstToDistinguishByPosition(args1, args2)}; 160964ab3302SCarolineConcatto int name1{FindLastToDistinguishByName(args1, args2)}; 161064ab3302SCarolineConcatto if (pos1 >= 0 && pos1 <= name1) { 161164ab3302SCarolineConcatto return true; // distinguishable based on C1514 rule 4 161264ab3302SCarolineConcatto } 161364ab3302SCarolineConcatto int pos2{FindFirstToDistinguishByPosition(args2, args1)}; 161464ab3302SCarolineConcatto int name2{FindLastToDistinguishByName(args2, args1)}; 161564ab3302SCarolineConcatto if (pos2 >= 0 && pos2 <= name2) { 161664ab3302SCarolineConcatto return true; // distinguishable based on C1514 rule 4 161764ab3302SCarolineConcatto } 1618f513bd80SPeter Klausler if (proc1.cudaSubprogramAttrs != proc2.cudaSubprogramAttrs) { 1619f513bd80SPeter Klausler return true; 1620f513bd80SPeter Klausler } 16213d115700SPeter Klausler // If there are no optional or unlimited polymorphic dummy arguments, 16223d115700SPeter Klausler // then we know the result for sure; otherwise, it's possible for 16233d115700SPeter Klausler // the procedures to be unambiguous. 16243d115700SPeter Klausler if ((AnyOptionalData(args1) || AnyUnlimitedPolymorphicData(args1)) && 16253d115700SPeter Klausler (AnyOptionalData(args2) || AnyUnlimitedPolymorphicData(args2))) { 16263d115700SPeter Klausler return std::nullopt; // meaning "maybe" 16273d115700SPeter Klausler } else { 16283d115700SPeter Klausler return false; 16293d115700SPeter Klausler } 16303d115700SPeter Klausler } 16313d115700SPeter Klausler 16323d115700SPeter Klausler bool DistinguishUtils::AnyOptionalData(const DummyArguments &args) const { 16333d115700SPeter Klausler for (const auto &arg : args) { 16343d115700SPeter Klausler if (std::holds_alternative<DummyDataObject>(arg.u) && arg.IsOptional()) { 16353d115700SPeter Klausler return true; 16363d115700SPeter Klausler } 16373d115700SPeter Klausler } 16383d115700SPeter Klausler return false; 16393d115700SPeter Klausler } 16403d115700SPeter Klausler 16413d115700SPeter Klausler bool DistinguishUtils::AnyUnlimitedPolymorphicData( 16423d115700SPeter Klausler const DummyArguments &args) const { 16433d115700SPeter Klausler for (const auto &arg : args) { 16443d115700SPeter Klausler if (const auto *object{std::get_if<DummyDataObject>(&arg.u)}) { 16453d115700SPeter Klausler if (object->type.type().IsUnlimitedPolymorphic()) { 16463d115700SPeter Klausler return true; 16473d115700SPeter Klausler } 16483d115700SPeter Klausler } 16493d115700SPeter Klausler } 165064ab3302SCarolineConcatto return false; 165164ab3302SCarolineConcatto } 165264ab3302SCarolineConcatto 165364ab3302SCarolineConcatto // C1514 rule 3: Procedures are distinguishable if both have a passed-object 165464ab3302SCarolineConcatto // dummy argument and those are distinguishable. 165564ab3302SCarolineConcatto bool DistinguishUtils::Rule3Distinguishable( 1656c4ba1108Speter klausler const Procedure &proc1, const Procedure &proc2) const { 165764ab3302SCarolineConcatto const DummyArgument *pass1{GetPassArg(proc1)}; 165864ab3302SCarolineConcatto const DummyArgument *pass2{GetPassArg(proc2)}; 165964ab3302SCarolineConcatto return pass1 && pass2 && Distinguishable(*pass1, *pass2); 166064ab3302SCarolineConcatto } 166164ab3302SCarolineConcatto 166264ab3302SCarolineConcatto // Find a non-passed-object dummy data object in one of the argument lists 166364ab3302SCarolineConcatto // that satisfies C1514 rule 1. I.e. x such that: 166464ab3302SCarolineConcatto // - m is the number of dummy data objects in one that are nonoptional, 166564ab3302SCarolineConcatto // are not passed-object, that x is TKR compatible with 166664ab3302SCarolineConcatto // - n is the number of non-passed-object dummy data objects, in the other 166764ab3302SCarolineConcatto // that are not distinguishable from x 166864ab3302SCarolineConcatto // - m is greater than n 166964ab3302SCarolineConcatto const DummyArgument *DistinguishUtils::Rule1DistinguishingArg( 1670c4ba1108Speter klausler const DummyArguments &args1, const DummyArguments &args2) const { 167164ab3302SCarolineConcatto auto size1{args1.size()}; 167264ab3302SCarolineConcatto auto size2{args2.size()}; 167364ab3302SCarolineConcatto for (std::size_t i{0}; i < size1 + size2; ++i) { 167464ab3302SCarolineConcatto const DummyArgument &x{i < size1 ? args1[i] : args2[i - size1]}; 167564ab3302SCarolineConcatto if (!x.pass && std::holds_alternative<DummyDataObject>(x.u)) { 167664ab3302SCarolineConcatto if (CountCompatibleWith(x, args1) > 167764ab3302SCarolineConcatto CountNotDistinguishableFrom(x, args2) || 167864ab3302SCarolineConcatto CountCompatibleWith(x, args2) > 167964ab3302SCarolineConcatto CountNotDistinguishableFrom(x, args1)) { 168064ab3302SCarolineConcatto return &x; 168164ab3302SCarolineConcatto } 168264ab3302SCarolineConcatto } 168364ab3302SCarolineConcatto } 168464ab3302SCarolineConcatto return nullptr; 168564ab3302SCarolineConcatto } 168664ab3302SCarolineConcatto 168764ab3302SCarolineConcatto // Find the index of the first nonoptional non-passed-object dummy argument 168864ab3302SCarolineConcatto // in args1 at an effective position such that either: 168964ab3302SCarolineConcatto // - args2 has no dummy argument at that effective position 169064ab3302SCarolineConcatto // - the dummy argument at that position is distinguishable from it 169164ab3302SCarolineConcatto int DistinguishUtils::FindFirstToDistinguishByPosition( 1692c4ba1108Speter klausler const DummyArguments &args1, const DummyArguments &args2) const { 169364ab3302SCarolineConcatto int effective{0}; // position of arg1 in list, ignoring passed arg 169464ab3302SCarolineConcatto for (std::size_t i{0}; i < args1.size(); ++i) { 169564ab3302SCarolineConcatto const DummyArgument &arg1{args1.at(i)}; 169664ab3302SCarolineConcatto if (!arg1.pass && !arg1.IsOptional()) { 169764ab3302SCarolineConcatto const DummyArgument *arg2{GetAtEffectivePosition(args2, effective)}; 169864ab3302SCarolineConcatto if (!arg2 || Distinguishable(arg1, *arg2)) { 169964ab3302SCarolineConcatto return i; 170064ab3302SCarolineConcatto } 170164ab3302SCarolineConcatto } 170264ab3302SCarolineConcatto effective += !arg1.pass; 170364ab3302SCarolineConcatto } 170464ab3302SCarolineConcatto return -1; 170564ab3302SCarolineConcatto } 170664ab3302SCarolineConcatto 170764ab3302SCarolineConcatto // Find the index of the last nonoptional non-passed-object dummy argument 170864ab3302SCarolineConcatto // in args1 whose name is such that either: 170964ab3302SCarolineConcatto // - args2 has no dummy argument with that name 171064ab3302SCarolineConcatto // - the dummy argument with that name is distinguishable from it 171164ab3302SCarolineConcatto int DistinguishUtils::FindLastToDistinguishByName( 1712c4ba1108Speter klausler const DummyArguments &args1, const DummyArguments &args2) const { 171364ab3302SCarolineConcatto std::map<std::string, const DummyArgument *> nameToArg; 171464ab3302SCarolineConcatto for (const auto &arg2 : args2) { 171564ab3302SCarolineConcatto nameToArg.emplace(arg2.name, &arg2); 171664ab3302SCarolineConcatto } 171764ab3302SCarolineConcatto for (int i = args1.size() - 1; i >= 0; --i) { 171864ab3302SCarolineConcatto const DummyArgument &arg1{args1.at(i)}; 171964ab3302SCarolineConcatto if (!arg1.pass && !arg1.IsOptional()) { 172064ab3302SCarolineConcatto auto it{nameToArg.find(arg1.name)}; 172164ab3302SCarolineConcatto if (it == nameToArg.end() || Distinguishable(arg1, *it->second)) { 172264ab3302SCarolineConcatto return i; 172364ab3302SCarolineConcatto } 172464ab3302SCarolineConcatto } 172564ab3302SCarolineConcatto } 172664ab3302SCarolineConcatto return -1; 172764ab3302SCarolineConcatto } 172864ab3302SCarolineConcatto 172964ab3302SCarolineConcatto // Count the dummy data objects in args that are nonoptional, are not 173064ab3302SCarolineConcatto // passed-object, and that x is TKR compatible with 173164ab3302SCarolineConcatto int DistinguishUtils::CountCompatibleWith( 1732c4ba1108Speter klausler const DummyArgument &x, const DummyArguments &args) const { 17333850edd9SKazu Hirata return llvm::count_if(args, [&](const DummyArgument &y) { 173464ab3302SCarolineConcatto return !y.pass && !y.IsOptional() && IsTkrCompatible(x, y); 173564ab3302SCarolineConcatto }); 173664ab3302SCarolineConcatto } 173764ab3302SCarolineConcatto 173864ab3302SCarolineConcatto // Return the number of dummy data objects in args that are not 173964ab3302SCarolineConcatto // distinguishable from x and not passed-object. 174064ab3302SCarolineConcatto int DistinguishUtils::CountNotDistinguishableFrom( 1741c4ba1108Speter klausler const DummyArgument &x, const DummyArguments &args) const { 17423850edd9SKazu Hirata return llvm::count_if(args, [&](const DummyArgument &y) { 174364ab3302SCarolineConcatto return !y.pass && std::holds_alternative<DummyDataObject>(y.u) && 174464ab3302SCarolineConcatto !Distinguishable(y, x); 174564ab3302SCarolineConcatto }); 174664ab3302SCarolineConcatto } 174764ab3302SCarolineConcatto 174864ab3302SCarolineConcatto bool DistinguishUtils::Distinguishable( 1749c4ba1108Speter klausler const DummyArgument &x, const DummyArgument &y) const { 175064ab3302SCarolineConcatto if (x.u.index() != y.u.index()) { 175164ab3302SCarolineConcatto return true; // different kind: data/proc/alt-return 175264ab3302SCarolineConcatto } 1753cd03e96fSPeter Klausler return common::visit( 175464ab3302SCarolineConcatto common::visitors{ 175564ab3302SCarolineConcatto [&](const DummyDataObject &z) { 175664ab3302SCarolineConcatto return Distinguishable(z, std::get<DummyDataObject>(y.u)); 175764ab3302SCarolineConcatto }, 175864ab3302SCarolineConcatto [&](const DummyProcedure &z) { 175964ab3302SCarolineConcatto return Distinguishable(z, std::get<DummyProcedure>(y.u)); 176064ab3302SCarolineConcatto }, 176164ab3302SCarolineConcatto [&](const AlternateReturn &) { return false; }, 176264ab3302SCarolineConcatto }, 176364ab3302SCarolineConcatto x.u); 176464ab3302SCarolineConcatto } 176564ab3302SCarolineConcatto 176664ab3302SCarolineConcatto bool DistinguishUtils::Distinguishable( 1767c4ba1108Speter klausler const DummyDataObject &x, const DummyDataObject &y) const { 176864ab3302SCarolineConcatto using Attr = DummyDataObject::Attr; 1769864cb2aaSPeter Klausler if (Distinguishable(x.type, y.type, x.ignoreTKR | y.ignoreTKR)) { 177064ab3302SCarolineConcatto return true; 177164ab3302SCarolineConcatto } else if (x.attrs.test(Attr::Allocatable) && y.attrs.test(Attr::Pointer) && 177264ab3302SCarolineConcatto y.intent != common::Intent::In) { 177364ab3302SCarolineConcatto return true; 177464ab3302SCarolineConcatto } else if (y.attrs.test(Attr::Allocatable) && x.attrs.test(Attr::Pointer) && 177564ab3302SCarolineConcatto x.intent != common::Intent::In) { 177664ab3302SCarolineConcatto return true; 17773e930864SValentin Clement } else if (!common::AreCompatibleCUDADataAttrs(x.cudaDataAttr, y.cudaDataAttr, 177830d80009SValentin Clement (バレンタイン クレメン) x.ignoreTKR | y.ignoreTKR, nullptr, 17793e930864SValentin Clement /*allowUnifiedMatchingRule=*/false)) { 1780f513bd80SPeter Klausler return true; 1781c4ba1108Speter klausler } else if (features_.IsEnabled( 1782c4ba1108Speter klausler common::LanguageFeature::DistinguishableSpecifics) && 1783c4ba1108Speter klausler (x.attrs.test(Attr::Allocatable) || x.attrs.test(Attr::Pointer)) && 1784c4ba1108Speter klausler (y.attrs.test(Attr::Allocatable) || y.attrs.test(Attr::Pointer)) && 1785c4ba1108Speter klausler (x.type.type().IsUnlimitedPolymorphic() != 1786c4ba1108Speter klausler y.type.type().IsUnlimitedPolymorphic() || 1787c4ba1108Speter klausler x.type.type().IsPolymorphic() != y.type.type().IsPolymorphic())) { 1788c4ba1108Speter klausler // Extension: Per 15.5.2.5(2), an allocatable/pointer dummy and its 1789c4ba1108Speter klausler // corresponding actual argument must both or neither be polymorphic, 1790c4ba1108Speter klausler // and must both or neither be unlimited polymorphic. So when exactly 1791c4ba1108Speter klausler // one of two dummy arguments is polymorphic or unlimited polymorphic, 1792c4ba1108Speter klausler // any actual argument that is admissible to one of them cannot also match 1793c4ba1108Speter klausler // the other one. 1794c4ba1108Speter klausler return true; 179564ab3302SCarolineConcatto } else { 179664ab3302SCarolineConcatto return false; 179764ab3302SCarolineConcatto } 179864ab3302SCarolineConcatto } 179964ab3302SCarolineConcatto 180064ab3302SCarolineConcatto bool DistinguishUtils::Distinguishable( 1801c4ba1108Speter klausler const DummyProcedure &x, const DummyProcedure &y) const { 180264ab3302SCarolineConcatto const Procedure &xProc{x.procedure.value()}; 180364ab3302SCarolineConcatto const Procedure &yProc{y.procedure.value()}; 18043d115700SPeter Klausler if (Distinguishable(xProc, yProc).value_or(false)) { 180564ab3302SCarolineConcatto return true; 180664ab3302SCarolineConcatto } else { 180764ab3302SCarolineConcatto const std::optional<FunctionResult> &xResult{xProc.functionResult}; 180864ab3302SCarolineConcatto const std::optional<FunctionResult> &yResult{yProc.functionResult}; 180964ab3302SCarolineConcatto return xResult ? !yResult || Distinguishable(*xResult, *yResult) 181064ab3302SCarolineConcatto : yResult.has_value(); 181164ab3302SCarolineConcatto } 181264ab3302SCarolineConcatto } 181364ab3302SCarolineConcatto 181464ab3302SCarolineConcatto bool DistinguishUtils::Distinguishable( 1815c4ba1108Speter klausler const FunctionResult &x, const FunctionResult &y) const { 181664ab3302SCarolineConcatto if (x.u.index() != y.u.index()) { 181764ab3302SCarolineConcatto return true; // one is data object, one is procedure 181864ab3302SCarolineConcatto } 1819f513bd80SPeter Klausler if (x.cudaDataAttr != y.cudaDataAttr) { 1820f513bd80SPeter Klausler return true; 1821f513bd80SPeter Klausler } 1822cd03e96fSPeter Klausler return common::visit( 182364ab3302SCarolineConcatto common::visitors{ 182464ab3302SCarolineConcatto [&](const TypeAndShape &z) { 1825864cb2aaSPeter Klausler return Distinguishable( 1826864cb2aaSPeter Klausler z, std::get<TypeAndShape>(y.u), common::IgnoreTKRSet{}); 182764ab3302SCarolineConcatto }, 182864ab3302SCarolineConcatto [&](const CopyableIndirection<Procedure> &z) { 182964ab3302SCarolineConcatto return Distinguishable(z.value(), 18303d115700SPeter Klausler std::get<CopyableIndirection<Procedure>>(y.u).value()) 18313d115700SPeter Klausler .value_or(false); 183264ab3302SCarolineConcatto }, 183364ab3302SCarolineConcatto }, 183464ab3302SCarolineConcatto x.u); 183564ab3302SCarolineConcatto } 183664ab3302SCarolineConcatto 1837864cb2aaSPeter Klausler bool DistinguishUtils::Distinguishable(const TypeAndShape &x, 1838864cb2aaSPeter Klausler const TypeAndShape &y, common::IgnoreTKRSet ignoreTKR) const { 1839864cb2aaSPeter Klausler if (!x.type().IsTkCompatibleWith(y.type(), ignoreTKR) && 1840864cb2aaSPeter Klausler !y.type().IsTkCompatibleWith(x.type(), ignoreTKR)) { 1841864cb2aaSPeter Klausler return true; 1842864cb2aaSPeter Klausler } 1843864cb2aaSPeter Klausler if (ignoreTKR.test(common::IgnoreTKR::Rank)) { 1844864cb2aaSPeter Klausler } else if (x.attrs().test(TypeAndShape::Attr::AssumedRank) || 1845864cb2aaSPeter Klausler y.attrs().test(TypeAndShape::Attr::AssumedRank)) { 1846864cb2aaSPeter Klausler } else if (x.Rank() != y.Rank()) { 1847864cb2aaSPeter Klausler return true; 1848864cb2aaSPeter Klausler } 1849864cb2aaSPeter Klausler return false; 185064ab3302SCarolineConcatto } 185164ab3302SCarolineConcatto 185264ab3302SCarolineConcatto // Compatibility based on type, kind, and rank 1853864cb2aaSPeter Klausler 185464ab3302SCarolineConcatto bool DistinguishUtils::IsTkrCompatible( 1855c4ba1108Speter klausler const DummyArgument &x, const DummyArgument &y) const { 185664ab3302SCarolineConcatto const auto *obj1{std::get_if<DummyDataObject>(&x.u)}; 185764ab3302SCarolineConcatto const auto *obj2{std::get_if<DummyDataObject>(&y.u)}; 1858864cb2aaSPeter Klausler return obj1 && obj2 && IsTkCompatible(*obj1, *obj2) && 1859864cb2aaSPeter Klausler (obj1->type.Rank() == obj2->type.Rank() || 1860864cb2aaSPeter Klausler obj1->type.attrs().test(TypeAndShape::Attr::AssumedRank) || 1861864cb2aaSPeter Klausler obj2->type.attrs().test(TypeAndShape::Attr::AssumedRank) || 1862864cb2aaSPeter Klausler obj1->ignoreTKR.test(common::IgnoreTKR::Rank) || 1863864cb2aaSPeter Klausler obj2->ignoreTKR.test(common::IgnoreTKR::Rank)); 186464ab3302SCarolineConcatto } 1865864cb2aaSPeter Klausler 1866864cb2aaSPeter Klausler bool DistinguishUtils::IsTkCompatible( 1867864cb2aaSPeter Klausler const DummyDataObject &x, const DummyDataObject &y) const { 1868864cb2aaSPeter Klausler return x.type.type().IsTkCompatibleWith( 1869864cb2aaSPeter Klausler y.type.type(), x.ignoreTKR | y.ignoreTKR); 187064ab3302SCarolineConcatto } 187164ab3302SCarolineConcatto 187264ab3302SCarolineConcatto // Return the argument at the given index, ignoring the passed arg 187364ab3302SCarolineConcatto const DummyArgument *DistinguishUtils::GetAtEffectivePosition( 1874c4ba1108Speter klausler const DummyArguments &args, int index) const { 187564ab3302SCarolineConcatto for (const DummyArgument &arg : args) { 187664ab3302SCarolineConcatto if (!arg.pass) { 187764ab3302SCarolineConcatto if (index == 0) { 187864ab3302SCarolineConcatto return &arg; 187964ab3302SCarolineConcatto } 188064ab3302SCarolineConcatto --index; 188164ab3302SCarolineConcatto } 188264ab3302SCarolineConcatto } 188364ab3302SCarolineConcatto return nullptr; 188464ab3302SCarolineConcatto } 188564ab3302SCarolineConcatto 188664ab3302SCarolineConcatto // Return the passed-object dummy argument of this procedure, if any 1887c4ba1108Speter klausler const DummyArgument *DistinguishUtils::GetPassArg(const Procedure &proc) const { 188864ab3302SCarolineConcatto for (const auto &arg : proc.dummyArguments) { 188964ab3302SCarolineConcatto if (arg.pass) { 189064ab3302SCarolineConcatto return &arg; 189164ab3302SCarolineConcatto } 189264ab3302SCarolineConcatto } 189364ab3302SCarolineConcatto return nullptr; 189464ab3302SCarolineConcatto } 189564ab3302SCarolineConcatto 18963d115700SPeter Klausler std::optional<bool> Distinguishable( 18973d115700SPeter Klausler const common::LanguageFeatureControl &features, const Procedure &x, 18983d115700SPeter Klausler const Procedure &y) { 1899c4ba1108Speter klausler return DistinguishUtils{features}.Distinguishable(x, y); 190064ab3302SCarolineConcatto } 190164ab3302SCarolineConcatto 19023d115700SPeter Klausler std::optional<bool> DistinguishableOpOrAssign( 19033d115700SPeter Klausler const common::LanguageFeatureControl &features, const Procedure &x, 19043d115700SPeter Klausler const Procedure &y) { 1905c4ba1108Speter klausler return DistinguishUtils{features}.DistinguishableOpOrAssign(x, y); 190664ab3302SCarolineConcatto } 190764ab3302SCarolineConcatto 190864ab3302SCarolineConcatto DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(DummyArgument) 190964ab3302SCarolineConcatto DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(DummyProcedure) 191064ab3302SCarolineConcatto DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(FunctionResult) 191164ab3302SCarolineConcatto DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(Procedure) 19121f879005STim Keith } // namespace Fortran::evaluate::characteristics 191364ab3302SCarolineConcatto 191464ab3302SCarolineConcatto template class Fortran::common::Indirection< 191564ab3302SCarolineConcatto Fortran::evaluate::characteristics::Procedure, true>; 1916