static std::optional<TypeAndShape> Characterize(
const semantics::Symbol &, FoldingContext &);
static std::optional<TypeAndShape> Characterize(
- const semantics::ObjectEntityDetails &, FoldingContext &);
- static std::optional<TypeAndShape> Characterize(
const semantics::ProcInterface &, FoldingContext &);
static std::optional<TypeAndShape> Characterize(
const semantics::DeclTypeSpec &, FoldingContext &);
static std::optional<TypeAndShape> Characterize(
const ActualArgument &, FoldingContext &);
+ // Handle Expr<T> & Designator<T>
template <typename A>
static std::optional<TypeAndShape> Characterize(
const A &x, FoldingContext &context) {
- if (const auto *symbol{UnwrapWholeSymbolDataRef(x)}) {
+ if (const auto *symbol{UnwrapWholeSymbolOrComponentDataRef(x)}) {
if (auto result{Characterize(*symbol, context)}) {
return result;
}
}
if (auto type{x.GetType()}) {
- if (auto shape{GetShape(context, x)}) {
- TypeAndShape result{*type, std::move(*shape)};
- if (type->category() == TypeCategory::Character) {
- if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(x)}) {
- if (auto length{chExpr->LEN()}) {
- result.set_LEN(std::move(*length));
- }
+ TypeAndShape result{*type, GetShape(context, x)};
+ if (type->category() == TypeCategory::Character) {
+ if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(x)}) {
+ if (auto length{chExpr->LEN()}) {
+ result.set_LEN(std::move(*length));
}
}
- return std::move(result.Rewrite(context));
}
+ return std::move(result.Rewrite(context));
}
return std::nullopt;
}
const semantics::AssocEntityDetails &, FoldingContext &);
static std::optional<TypeAndShape> Characterize(
const semantics::ProcEntityDetails &, FoldingContext &);
- void AcquireShape(const semantics::ObjectEntityDetails &);
+ void AcquireAttrs(const semantics::Symbol &);
void AcquireLEN();
+ void AcquireLEN(const semantics::Symbol &);
protected:
DynamicType type_;
return nullptr;
}
+// If an expression is a whole symbol or a whole component desginator,
+// extract and return that symbol, else null.
+template <typename A>
+const Symbol *UnwrapWholeSymbolOrComponentDataRef(const A &x) {
+ if (auto dataRef{ExtractDataRef(x)}) {
+ if (const SymbolRef * p{std::get_if<SymbolRef>(&dataRef->u)}) {
+ return &p->get();
+ } else if (const Component * c{std::get_if<Component>(&dataRef->u)}) {
+ if (c->base().Rank() == 0) {
+ return &c->GetLastSymbol();
+ }
+ }
+ }
+ return nullptr;
+}
+
// GetFirstSymbol(A%B%C[I]%D) -> A
template <typename A> const Symbol *GetFirstSymbol(const A &x) {
if (auto dataRef{ExtractDataRef(x, true)}) {
std::optional<TypeAndShape> TypeAndShape::Characterize(
const semantics::Symbol &symbol, FoldingContext &context) {
+ const auto &ultimate{symbol.GetUltimate()};
return std::visit(
common::visitors{
- [&](const semantics::ObjectEntityDetails &object) {
- auto result{Characterize(object, context)};
- if (result &&
- result->type().category() == TypeCategory::Character) {
- if (auto len{DataRef{symbol}.LEN()}) {
- result->set_LEN(Fold(context, std::move(*len)));
- }
+ [&](const semantics::ObjectEntityDetails &object)
+ -> std::optional<TypeAndShape> {
+ if (auto type{DynamicType::From(object.type())}) {
+ TypeAndShape result{
+ std::move(*type), GetShape(context, ultimate)};
+ result.AcquireAttrs(ultimate);
+ result.AcquireLEN(ultimate);
+ return std::move(result.Rewrite(context));
+ } else {
+ return std::nullopt;
}
- return result;
},
[&](const semantics::ProcEntityDetails &proc) {
const semantics::ProcInterface &interface{proc.interface()};
// GetUltimate() used here, not ResolveAssociations(), because
// we need the type/rank of an associate entity from TYPE IS,
// CLASS IS, or RANK statement.
- symbol.GetUltimate().details());
-}
-
-std::optional<TypeAndShape> TypeAndShape::Characterize(
- const semantics::ObjectEntityDetails &object, FoldingContext &context) {
- if (auto type{DynamicType::From(object.type())}) {
- TypeAndShape result{std::move(*type)};
- result.AcquireShape(object);
- return Fold(context, std::move(result));
- } else {
- return std::nullopt;
- }
+ ultimate.details());
}
std::optional<TypeAndShape> TypeAndShape::Characterize(
return std::nullopt;
}
-void TypeAndShape::AcquireShape(const semantics::ObjectEntityDetails &object) {
- CHECK(shape_.empty() && !attrs_.test(Attr::AssumedRank));
- corank_ = object.coshape().Rank();
- if (object.IsAssumedRank()) {
- attrs_.set(Attr::AssumedRank);
- return;
- }
- if (object.IsAssumedShape()) {
- attrs_.set(Attr::AssumedShape);
- }
- if (object.IsAssumedSize()) {
- attrs_.set(Attr::AssumedSize);
- }
- if (object.IsDeferredShape()) {
- attrs_.set(Attr::DeferredShape);
- }
- if (object.IsCoarray()) {
- attrs_.set(Attr::Coarray);
- }
- for (const semantics::ShapeSpec &dim : object.shape()) {
- if (dim.ubound().GetExplicit()) {
- Expr<SubscriptInteger> extent{*dim.ubound().GetExplicit()};
- if (auto lbound{dim.lbound().GetExplicit()}) {
- extent =
- std::move(extent) + Expr<SubscriptInteger>{1} - std::move(*lbound);
- }
- shape_.emplace_back(std::move(extent));
- } else {
- shape_.push_back(std::nullopt);
+void TypeAndShape::AcquireAttrs(const semantics::Symbol &symbol) {
+ if (const auto *object{
+ symbol.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()}) {
+ corank_ = object->coshape().Rank();
+ if (object->IsAssumedRank()) {
+ attrs_.set(Attr::AssumedRank);
+ }
+ if (object->IsAssumedShape()) {
+ attrs_.set(Attr::AssumedShape);
+ }
+ if (object->IsAssumedSize()) {
+ attrs_.set(Attr::AssumedSize);
+ }
+ if (object->IsDeferredShape()) {
+ attrs_.set(Attr::DeferredShape);
+ }
+ if (object->IsCoarray()) {
+ attrs_.set(Attr::Coarray);
}
}
}
}
}
+void TypeAndShape::AcquireLEN(const semantics::Symbol &symbol) {
+ if (type_.category() == TypeCategory::Character) {
+ if (auto len{DataRef{symbol}.LEN()}) {
+ LEN_ = std::move(*len);
+ }
+ }
+}
+
llvm::raw_ostream &TypeAndShape::Dump(llvm::raw_ostream &o) const {
o << type_.AsFortran(LEN_ ? LEN_->AsFortran() : "");
attrs_.Dump(o, EnumToString);
std::optional<DummyDataObject> DummyDataObject::Characterize(
const semantics::Symbol &symbol, FoldingContext &context) {
- if (const auto *obj{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
- if (auto type{TypeAndShape::Characterize(*obj, context)}) {
+ if (symbol.has<semantics::ObjectEntityDetails>()) {
+ if (auto type{TypeAndShape::Characterize(symbol, context)}) {
std::optional<DummyDataObject> result{std::move(*type)};
using semantics::Attr;
CopyAttrs<DummyDataObject, DummyDataObject::Attr>(symbol, *result,
std::optional<FunctionResult> FunctionResult::Characterize(
const Symbol &symbol, FoldingContext &context) {
- if (const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
- if (auto type{TypeAndShape::Characterize(*object, context)}) {
+ if (symbol.has<semantics::ObjectEntityDetails>()) {
+ if (auto type{TypeAndShape::Characterize(symbol, context)}) {
FunctionResult result{std::move(*type)};
CopyAttrs<FunctionResult, FunctionResult::Attr>(symbol, result,
{
CHECK(dimension >= 0);
const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())};
if (const auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
- if (IsImpliedShape(symbol)) {
- Shape shape{GetShape(symbol).value()};
- return std::move(shape.at(dimension));
- }
- int j{0};
- for (const auto &shapeSpec : details->shape()) {
- if (j++ == dimension) {
- if (shapeSpec.ubound().isExplicit()) {
- if (const auto &ubound{shapeSpec.ubound().GetExplicit()}) {
- if (const auto &lbound{shapeSpec.lbound().GetExplicit()}) {
- return common::Clone(ubound.value()) -
- common::Clone(lbound.value()) + ExtentExpr{1};
- } else {
- return ubound.value();
+ if (IsImpliedShape(symbol) && details->init()) {
+ if (auto shape{GetShape(symbol)}) {
+ if (dimension < static_cast<int>(shape->size())) {
+ return std::move(shape->at(dimension));
+ }
+ }
+ } else {
+ int j{0};
+ for (const auto &shapeSpec : details->shape()) {
+ if (j++ == dimension) {
+ if (shapeSpec.ubound().isExplicit()) {
+ if (const auto &ubound{shapeSpec.ubound().GetExplicit()}) {
+ if (const auto &lbound{shapeSpec.lbound().GetExplicit()}) {
+ return common::Clone(ubound.value()) -
+ common::Clone(lbound.value()) + ExtentExpr{1};
+ } else {
+ return ubound.value();
+ }
}
+ } else if (details->IsAssumedSize() && j == symbol.Rank()) {
+ return std::nullopt;
+ } else if (semantics::IsDescriptor(symbol)) {
+ return ExtentExpr{DescriptorInquiry{NamedEntity{base},
+ DescriptorInquiry::Field::Extent, dimension}};
}
- } else if (details->IsAssumedSize() && j == symbol.Rank()) {
- return std::nullopt;
- } else if (semantics::IsDescriptor(symbol)) {
- return ExtentExpr{DescriptorInquiry{
- NamedEntity{base}, DescriptorInquiry::Field::Extent, dimension}};
}
}
}
return std::visit(
common::visitors{
[&](const semantics::ObjectEntityDetails &object) {
- if (IsImpliedShape(symbol)) {
+ if (IsImpliedShape(symbol) && object.init()) {
return (*this)(object.init());
} else {
int n{object.shape().Rank()};
#include "flang/Parser/char-block.h"
#include "flang/Parser/characters.h"
#include "flang/Parser/message.h"
+#include "flang/Semantics/scope.h"
#include "flang/Semantics/symbol.h"
#include <type_traits>
}
// LEN()
-static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &sym) {
- if (auto dyType{DynamicType::From(sym)}) {
+static std::optional<Expr<SubscriptInteger>> SymbolLEN(const Symbol &symbol) {
+ const Symbol &ultimate{symbol.GetUltimate()};
+ if (const auto *assoc{ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
+ if (const auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(assoc->expr())}) {
+ return chExpr->LEN();
+ }
+ } else if (auto dyType{DynamicType::From(ultimate)}) {
if (const semantics::ParamValue * len{dyType->charLength()}) {
if (len->isExplicit()) {
if (auto intExpr{len->GetExplicit()}) {
}
}
}
- return Expr<SubscriptInteger>{
- DescriptorInquiry{NamedEntity{sym}, DescriptorInquiry::Field::Len}};
+ if (IsDescriptor(ultimate) && !ultimate.owner().IsDerivedType()) {
+ return Expr<SubscriptInteger>{DescriptorInquiry{
+ NamedEntity{ultimate}, DescriptorInquiry::Field::Len}};
+ }
}
}
return std::nullopt;
: nullptr};
int actualRank{evaluate::GetRank(actualType.shape())};
bool actualIsPointer{evaluate::IsObjectPointer(actual, context)};
+ bool dummyIsAssumedRank{dummy.type.attrs().test(
+ characteristics::TypeAndShape::Attr::AssumedRank)};
if (dummy.type.attrs().test(
characteristics::TypeAndShape::Attr::AssumedShape)) {
// 15.5.2.4(16)
if (!IsArrayElement(actual) &&
!(actualType.type().category() == TypeCategory::Character &&
actualType.type().kind() == 1) &&
- !(dummy.type.type().IsAssumedType() && dummyIsAssumedSize)) {
+ !(dummy.type.type().IsAssumedType() && dummyIsAssumedSize) &&
+ !dummyIsAssumedRank) {
messages.Say(
"Whole scalar actual argument may not be associated with a %s array"_err_en_US,
dummyName);
bool dummyIsContiguous{
dummy.attrs.test(characteristics::DummyDataObject::Attr::Contiguous)};
bool actualIsContiguous{IsSimplyContiguous(actual, context)};
- bool dummyIsAssumedRank{dummy.type.attrs().test(
- characteristics::TypeAndShape::Attr::AssumedRank)};
bool dummyIsAssumedShape{dummy.type.attrs().test(
characteristics::TypeAndShape::Attr::AssumedShape)};
if ((actualIsAsynchronous || actualIsVolatile) &&
return std::visit(
common::visitors{
[&](const characteristics::DummyDataObject &x) {
- characteristics::TypeAndShape dummyTypeAndShape{x.type};
- if (!isElemental && actual.Rank() != dummyTypeAndShape.Rank()) {
+ if (!isElemental && actual.Rank() != x.type.Rank() &&
+ !x.type.attrs().test(
+ characteristics::TypeAndShape::Attr::AssumedRank)) {
return false;
} else if (auto actualType{actual.GetType()}) {
- return dummyTypeAndShape.type().IsTkCompatibleWith(*actualType);
+ return x.type.type().IsTkCompatibleWith(*actualType);
} else {
return false;
}
const std::string &distinctName, const SymbolVector *parameters) {
evaluate::StructureConstructorValues values;
auto typeAndShape{evaluate::characteristics::TypeAndShape::Characterize(
- object, context_.foldingContext())};
+ symbol, context_.foldingContext())};
CHECK(typeAndShape.has_value());
auto dyType{typeAndShape->type()};
const auto &shape{typeAndShape->shape()};