diff --git a/flang/lib/evaluate/CMakeLists.txt b/flang/lib/evaluate/CMakeLists.txt index 3c5a14a0e236..ce5327436feb 100644 --- a/flang/lib/evaluate/CMakeLists.txt +++ b/flang/lib/evaluate/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -31,5 +31,5 @@ add_library(FortranEvaluate target_link_libraries(FortranEvaluate FortranCommon - FortranSemantics + FortranParser ) diff --git a/flang/lib/evaluate/type.cc b/flang/lib/evaluate/type.cc index 1a6eb4409a0c..79ba99430378 100644 --- a/flang/lib/evaluate/type.cc +++ b/flang/lib/evaluate/type.cc @@ -15,6 +15,7 @@ #include "type.h" #include "fold.h" #include "../common/idioms.h" +#include "../semantics/scope.h" #include "../semantics/symbol.h" #include "../semantics/type.h" #include @@ -23,6 +24,66 @@ using namespace std::literals::string_literals; +// IsDescriptor() predicate +namespace Fortran::semantics { +static bool IsDescriptor(const ObjectEntityDetails &details) { + if (const auto *type{details.type()}) { + if (const IntrinsicTypeSpec * typeSpec{type->AsIntrinsic()}) { + if (typeSpec->category() == TypeCategory::Character) { + // TODO maybe character lengths won't be in descriptors + return true; + } + } else if (const DerivedTypeSpec * typeSpec{type->AsDerived()}) { + if (details.isDummy()) { + return true; + } + // Any length type parameter? + if (const Scope * scope{typeSpec->scope()}) { + if (const Symbol * symbol{scope->symbol()}) { + if (const auto *details{symbol->detailsIf()}) { + for (const Symbol *param : details->paramDecls()) { + if (const auto *details{param->detailsIf()}) { + if (details->attr() == common::TypeParamAttr::Len) { + return true; + } + } + } + } + } + } + } else if (type->category() == DeclTypeSpec::Category::TypeStar || + type->category() == DeclTypeSpec::Category::ClassStar) { + return true; + } + } + if (details.IsAssumedShape() || details.IsDeferredShape() || + details.IsAssumedRank()) { + return true; + } + // TODO: Explicit shape component array dependent on length parameter + // TODO: Automatic (adjustable) arrays + return false; +} + +static bool IsDescriptor(const ProcEntityDetails &details) { + // A procedure pointer or dummy procedure must be a descriptor if + // and only if it requires a static link. + return details.HasExplicitInterface(); +} + +static bool IsDescriptor(const Symbol &symbol) { + if (const auto *objectDetails{symbol.detailsIf()}) { + return IsDescriptor(*objectDetails); + } else if (const auto *procDetails{symbol.detailsIf()}) { + if (symbol.attrs().test(Attr::POINTER) || + symbol.attrs().test(Attr::EXTERNAL)) { + return IsDescriptor(*procDetails); + } + } + return false; +} +} + namespace Fortran::evaluate { bool DynamicType::operator==(const DynamicType &that) const { @@ -38,7 +99,7 @@ std::optional GetSymbolType(const semantics::Symbol *symbol) { TypeCategory category{intrinsic->category()}; if (IsValidKindOfIntrinsicType(category, *kind)) { DynamicType dyType{category, static_cast(*kind)}; - if (symbol->IsDescriptor()) { + if (semantics::IsDescriptor(*symbol)) { dyType.descriptor = symbol; } return std::make_optional(std::move(dyType)); @@ -46,7 +107,7 @@ std::optional GetSymbolType(const semantics::Symbol *symbol) { } } else if (const auto *derived{type->AsDerived()}) { DynamicType dyType{TypeCategory::Derived, 0, derived}; - if (symbol->IsDescriptor()) { + if (semantics::IsDescriptor(*symbol)) { dyType.descriptor = symbol; } return std::make_optional(std::move(dyType)); diff --git a/flang/lib/semantics/CMakeLists.txt b/flang/lib/semantics/CMakeLists.txt index d3642e96028c..6e0b348b0da6 100644 --- a/flang/lib/semantics/CMakeLists.txt +++ b/flang/lib/semantics/CMakeLists.txt @@ -32,5 +32,6 @@ add_library(FortranSemantics target_link_libraries(FortranSemantics FortranCommon + FortranEvaluate clangBasic ) diff --git a/flang/lib/semantics/scope.cc b/flang/lib/semantics/scope.cc index 6f7817825296..1fafb017c60d 100644 --- a/flang/lib/semantics/scope.cc +++ b/flang/lib/semantics/scope.cc @@ -35,9 +35,6 @@ Scope &Scope::MakeScope(Kind kind, Symbol *symbol) { Scope::iterator Scope::find(const SourceName &name) { return symbols_.find(name); } -Scope::const_iterator Scope::find(const SourceName &name) const { - return symbols_.find(name); -} Scope::size_type Scope::erase(const SourceName &name) { auto it{symbols_.find(name)}; if (it != end()) { diff --git a/flang/lib/semantics/scope.h b/flang/lib/semantics/scope.h index 4010ed97431e..8a807734b9f3 100644 --- a/flang/lib/semantics/scope.h +++ b/flang/lib/semantics/scope.h @@ -91,7 +91,9 @@ public: const_iterator cend() const { return symbols_.cend(); } iterator find(const SourceName &name); - const_iterator find(const SourceName &name) const; + const_iterator find(const SourceName &name) const { + return symbols_.find(name); + } size_type erase(const SourceName &); size_type size() const { return symbols_.size(); } bool empty() const { return symbols_.empty(); } diff --git a/flang/lib/semantics/symbol.cc b/flang/lib/semantics/symbol.cc index e34c50423289..814c94212af5 100644 --- a/flang/lib/semantics/symbol.cc +++ b/flang/lib/semantics/symbol.cc @@ -83,54 +83,12 @@ void ObjectEntityDetails::set_shape(const ArraySpec &shape) { } } -bool ObjectEntityDetails::IsDescriptor() const { - if (const auto *type{this->type()}) { - if (const IntrinsicTypeSpec * typeSpec{type->AsIntrinsic()}) { - if (typeSpec->category() == TypeCategory::Character) { - // TODO maybe character lengths won't be in descriptors - return true; - } - } else if (const DerivedTypeSpec * typeSpec{type->AsDerived()}) { - if (isDummy()) { - return true; - } - // Any length type parameter? - if (const Scope * scope{typeSpec->scope()}) { - if (const Symbol * symbol{scope->symbol()}) { - if (const auto *details{symbol->detailsIf()}) { - for (const Symbol *param : details->paramDecls()) { - if (const auto *details{param->detailsIf()}) { - if (details->attr() == common::TypeParamAttr::Len) { - return true; - } - } - } - } - } - } - } else if (type->category() == DeclTypeSpec::Category::TypeStar || - type->category() == DeclTypeSpec::Category::ClassStar) { - return true; - } - } - if (IsAssumedShape() || IsDeferredShape() || IsAssumedRank()) { - return true; - } - // TODO: Explicit shape component array dependent on length parameter - // TODO: Automatic (adjustable) arrays - return false; -} - ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) { if (type()) { interface_.set_type(*type()); } } -// A procedure pointer or dummy procedure must be a descriptor if -// and only if it requires a static link. -bool ProcEntityDetails::IsDescriptor() const { return HasExplicitInterface(); } - const Symbol &UseDetails::module() const { // owner is a module so it must have a symbol: return *symbol_->owner().symbol(); @@ -229,7 +187,7 @@ bool Symbol::CanReplaceDetails(const Details &details) const { } Symbol &Symbol::GetUltimate() { - return const_cast(static_cast(this)->GetUltimate()); + return const_cast(const_cast(this)->GetUltimate()); } const Symbol &Symbol::GetUltimate() const { if (const auto *details{detailsIf()}) { @@ -241,24 +199,6 @@ const Symbol &Symbol::GetUltimate() const { } } -DeclTypeSpec *Symbol::GetType() { - return const_cast( - const_cast(this)->GetType()); -} - -const DeclTypeSpec *Symbol::GetType() const { - return std::visit( - common::visitors{ - [](const EntityDetails &x) { return x.type(); }, - [](const ObjectEntityDetails &x) { return x.type(); }, - [](const AssocEntityDetails &x) { return x.type(); }, - [](const ProcEntityDetails &x) { return x.interface().type(); }, - [](const TypeParamDetails &x) { return x.type(); }, - [](const auto &) -> const DeclTypeSpec * { return nullptr; }, - }, - details_); -} - void Symbol::SetType(const DeclTypeSpec &type) { std::visit( common::visitors{ @@ -284,18 +224,6 @@ bool Symbol::IsSubprogram() const { details_); } -bool Symbol::HasExplicitInterface() const { - return std::visit( - common::visitors{ - [](const SubprogramDetails &) { return true; }, - [](const SubprogramNameDetails &) { return true; }, - [](const ProcEntityDetails &x) { return x.HasExplicitInterface(); }, - [](const UseDetails &x) { return x.symbol().HasExplicitInterface(); }, - [](const auto &) { return false; }, - }, - details_); -} - bool Symbol::IsSeparateModuleProc() const { if (attrs().test(Attr::MODULE)) { if (auto *details{detailsIf()}) { @@ -305,40 +233,6 @@ bool Symbol::IsSeparateModuleProc() const { return false; } -bool Symbol::IsDescriptor() const { - if (const auto *objectDetails{detailsIf()}) { - return objectDetails->IsDescriptor(); - } else if (const auto *procDetails{detailsIf()}) { - if (attrs_.test(Attr::POINTER) || attrs_.test(Attr::EXTERNAL)) { - return procDetails->IsDescriptor(); - } - } - return false; -} - -int Symbol::Rank() const { - return std::visit( - common::visitors{ - [](const SubprogramDetails &sd) { - if (sd.isFunction()) { - return sd.result().Rank(); - } else { - return 0; - } - }, - [](const GenericDetails &) { - return 0; /*TODO*/ - }, - [](const UseDetails &x) { return x.symbol().Rank(); }, - [](const HostAssocDetails &x) { return x.symbol().Rank(); }, - [](const ObjectEntityDetails &oed) { - return static_cast(oed.shape().size()); - }, - [](const auto &) { return 0; }, - }, - details_); -} - ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d) : EntityDetails(d) {} @@ -374,13 +268,6 @@ std::ostream &operator<<(std::ostream &os, const AssocEntityDetails &x) { return os; } -bool ProcEntityDetails::HasExplicitInterface() const { - if (auto *symbol{interface_.symbol()}) { - return symbol->HasExplicitInterface(); - } - return false; -} - std::ostream &operator<<(std::ostream &os, const ProcEntityDetails &x) { if (auto *symbol{x.interface_.symbol()}) { os << ' ' << symbol->name(); diff --git a/flang/lib/semantics/symbol.h b/flang/lib/semantics/symbol.h index 045e96c0b326..e9a0e9348f42 100644 --- a/flang/lib/semantics/symbol.h +++ b/flang/lib/semantics/symbol.h @@ -168,7 +168,6 @@ public: return isDummy() && IsArray() && shape_.back().ubound().isAssumed() && shape_.back().lbound().isAssumed(); } - bool IsDescriptor() const; private: MaybeExpr init_; @@ -185,10 +184,9 @@ public: const ProcInterface &interface() const { return interface_; } ProcInterface &interface() { return interface_; } void set_interface(const ProcInterface &interface) { interface_ = interface; } - bool HasExplicitInterface() const; - bool IsDescriptor() const; const std::optional &passName() const { return passName_; } void set_passName(const SourceName &passName) { passName_ = passName; } + inline bool HasExplicitInterface() const; private: ProcInterface interface_; @@ -403,15 +401,12 @@ public: // Return a reference to the details which must be of type D. template D &get() { - return const_cast(static_cast(this)->get()); + return const_cast(const_cast(this)->get()); } template const D &get() const { - if (const auto p{detailsIf()}) { - return *p; - } else { - common::die("unexpected %s details at %s(%d)", GetDetailsName().c_str(), - __FILE__, __LINE__); - } + const auto *p{detailsIf()}; + CHECK(p != nullptr); + return *p; } Details &details() { return details_; } @@ -427,19 +422,67 @@ public: Symbol &GetUltimate(); const Symbol &GetUltimate() const; - DeclTypeSpec *GetType(); - const DeclTypeSpec *GetType() const; + DeclTypeSpec *GetType() { + return const_cast( + const_cast(this)->GetType()); + } + + const DeclTypeSpec *GetType() const { + return std::visit( + common::visitors{ + [](const EntityDetails &x) { return x.type(); }, + [](const ObjectEntityDetails &x) { return x.type(); }, + [](const AssocEntityDetails &x) { return x.type(); }, + [](const ProcEntityDetails &x) { return x.interface().type(); }, + [](const TypeParamDetails &x) { return x.type(); }, + [](const auto &) -> const DeclTypeSpec * { return nullptr; }, + }, + details_); + } + void SetType(const DeclTypeSpec &); bool IsSubprogram() const; - bool HasExplicitInterface() const; bool IsSeparateModuleProc() const; - bool IsDescriptor() const; + bool HasExplicitInterface() const { + return std::visit( + common::visitors{ + [](const SubprogramDetails &) { return true; }, + [](const SubprogramNameDetails &) { return true; }, + [](const ProcEntityDetails &x) { return x.HasExplicitInterface(); }, + [](const UseDetails &x) { + return x.symbol().HasExplicitInterface(); + }, + [](const auto &) { return false; }, + }, + details_); + } bool operator==(const Symbol &that) const { return this == &that; } bool operator!=(const Symbol &that) const { return this != &that; } - int Rank() const; + int Rank() const { + return std::visit( + common::visitors{ + [](const SubprogramDetails &sd) { + if (sd.isFunction()) { + return sd.result().Rank(); + } else { + return 0; + } + }, + [](const GenericDetails &) { + return 0; /*TODO*/ + }, + [](const UseDetails &x) { return x.symbol().Rank(); }, + [](const HostAssocDetails &x) { return x.symbol().Rank(); }, + [](const ObjectEntityDetails &oed) { + return static_cast(oed.shape().size()); + }, + [](const auto &) { return 0; }, + }, + details_); + } // Clones the Symbol in the context of a parameterized derived type instance Symbol &Instantiate(Scope &, evaluate::FoldingContext &) const; @@ -506,5 +549,16 @@ private: return result; } }; + +// Define a few member functions here in the header so that they +// can be used by lib/evaluate without inducing a dependence cycle +// between the two shared libraries. + +inline bool ProcEntityDetails::HasExplicitInterface() const { + if (auto *symbol{interface_.symbol()}) { + return symbol->HasExplicitInterface(); + } + return false; +} } #endif // FORTRAN_SEMANTICS_SYMBOL_H_ diff --git a/flang/lib/semantics/type.cc b/flang/lib/semantics/type.cc index 5f71e8794488..ce3406556677 100644 --- a/flang/lib/semantics/type.cc +++ b/flang/lib/semantics/type.cc @@ -50,21 +50,8 @@ ParamValue &DerivedTypeSpec::AddParamValue( } ParamValue *DerivedTypeSpec::FindParameter(SourceName target) { - auto iter{parameters_.find(target)}; - if (iter != parameters_.end()) { - return &iter->second; - } else { - return nullptr; - } -} - -const ParamValue *DerivedTypeSpec::FindParameter(SourceName target) const { - auto iter{parameters_.find(target)}; - if (iter != parameters_.end()) { - return &iter->second; - } else { - return nullptr; - } + return const_cast( + const_cast(this)->FindParameter(target)); } void DerivedTypeSpec::FoldParameterExpressions( @@ -278,27 +265,8 @@ bool DeclTypeSpec::IsNumeric(TypeCategory tc) const { return category_ == Numeric && numericTypeSpec().category() == tc; } IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() { - switch (category_) { - case Numeric: return &std::get(typeSpec_); - case Logical: return &std::get(typeSpec_); - case Character: return &std::get(typeSpec_); - default: return nullptr; - } -} -const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const { - switch (category_) { - case Numeric: return &std::get(typeSpec_); - case Logical: return &std::get(typeSpec_); - case Character: return &std::get(typeSpec_); - default: return nullptr; - } -} -const DerivedTypeSpec *DeclTypeSpec::AsDerived() const { - switch (category_) { - case TypeDerived: - case ClassDerived: return &std::get(typeSpec_); - default: return nullptr; - } + return const_cast( + const_cast(this)->AsIntrinsic()); } const NumericTypeSpec &DeclTypeSpec::numericTypeSpec() const { CHECK(category_ == Numeric); diff --git a/flang/lib/semantics/type.h b/flang/lib/semantics/type.h index ca8865f3b9e5..5223408cbdff 100644 --- a/flang/lib/semantics/type.h +++ b/flang/lib/semantics/type.h @@ -229,7 +229,14 @@ public: bool HasActualParameters() const { return !parameters_.empty(); } ParamValue &AddParamValue(SourceName, ParamValue &&); ParamValue *FindParameter(SourceName); - const ParamValue *FindParameter(SourceName) const; + const ParamValue *FindParameter(SourceName target) const { + auto iter{parameters_.find(target)}; + if (iter != parameters_.end()) { + return &iter->second; + } else { + return nullptr; + } + } void FoldParameterExpressions(evaluate::FoldingContext &); void Instantiate(Scope &, evaluate::FoldingContext &); bool operator==(const DerivedTypeSpec &) const; // for std::find() @@ -271,15 +278,30 @@ public: Category category() const { return category_; } void set_category(Category category) { category_ = category; } bool IsNumeric(TypeCategory) const; - IntrinsicTypeSpec *AsIntrinsic(); - const IntrinsicTypeSpec *AsIntrinsic() const; - const DerivedTypeSpec *AsDerived() const; const NumericTypeSpec &numericTypeSpec() const; const LogicalTypeSpec &logicalTypeSpec() const; const CharacterTypeSpec &characterTypeSpec() const; const DerivedTypeSpec &derivedTypeSpec() const; DerivedTypeSpec &derivedTypeSpec(); + IntrinsicTypeSpec *AsIntrinsic(); + const IntrinsicTypeSpec *AsIntrinsic() const { + switch (category_) { + case Numeric: return &std::get(typeSpec_); + case Logical: return &std::get(typeSpec_); + case Character: return &std::get(typeSpec_); + default: return nullptr; + } + } + + const DerivedTypeSpec *AsDerived() const { + switch (category_) { + case TypeDerived: + case ClassDerived: return &std::get(typeSpec_); + default: return nullptr; + } + } + private: Category category_; std::variant