diff --git a/flang/include/flang/Evaluate/shape.h b/flang/include/flang/Evaluate/shape.h index c7f453c90f0b..00724c259b2c 100644 --- a/flang/include/flang/Evaluate/shape.h +++ b/flang/include/flang/Evaluate/shape.h @@ -53,6 +53,8 @@ std::optional AsConstantExtents( inline int GetRank(const Shape &s) { return static_cast(s.size()); } +template std::optional GetShape(FoldingContext &, const A &); + // The dimension argument to these inquiries is zero-based, // unlike the DIM= arguments to many intrinsics. ExtentExpr GetLowerBound(FoldingContext &, const NamedEntity &, int dimension); @@ -80,16 +82,13 @@ MaybeExtentExpr GetSize(Shape &&); // Utility predicate: does an expression reference any implied DO index? bool ContainsAnyImpliedDoIndex(const ExtentExpr &); -// GetShape() -template std::optional GetShape(FoldingContext &, const A &); - class GetShapeHelper : public AnyTraverse> { public: using Result = std::optional; using Base = AnyTraverse; using Base::operator(); - GetShapeHelper(FoldingContext &c) : Base{*this}, context_{c} {} + explicit GetShapeHelper(FoldingContext &c) : Base{*this}, context_{c} {} Result operator()(const ImpliedDoIndex &) const { return Scalar(); } Result operator()(const DescriptorInquiry &) const { return Scalar(); } diff --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp index c0b59cff3c1f..f27ee5814075 100644 --- a/flang/lib/Evaluate/shape.cpp +++ b/flang/lib/Evaluate/shape.cpp @@ -177,52 +177,84 @@ bool ContainsAnyImpliedDoIndex(const ExtentExpr &expr) { return MyVisitor{}(expr); } -ExtentExpr GetLowerBound( - FoldingContext &context, const NamedEntity &base, int dimension) { - const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())}; +// Determines lower bound on a dimension. This can be other than 1 only +// for a reference to a whole array object or component. (See LBOUND, 16.9.109). +// ASSOCIATE construct entities may require tranversal of their referents. +class GetLowerBoundHelper : public Traverse { +public: + using Result = ExtentExpr; + using Base = Traverse; + using Base::operator(); + GetLowerBoundHelper(FoldingContext &c, int d) + : Base{*this}, context_{c}, dimension_{d} {} + static ExtentExpr Default() { return ExtentExpr{1}; } + static ExtentExpr Combine(Result &&, Result &&) { return Default(); } + ExtentExpr operator()(const Symbol &); + ExtentExpr operator()(const Component &); + +private: + FoldingContext &context_; + int dimension_; +}; + +auto GetLowerBoundHelper::operator()(const Symbol &symbol0) -> Result { + const Symbol &symbol{symbol0.GetUltimate()}; if (const auto *details{symbol.detailsIf()}) { int j{0}; for (const auto &shapeSpec : details->shape()) { - if (j++ == dimension) { + if (j++ == dimension_) { if (const auto &bound{shapeSpec.lbound().GetExplicit()}) { - return Fold(context, common::Clone(*bound)); + return Fold(context_, common::Clone(*bound)); } else if (semantics::IsDescriptor(symbol)) { - return ExtentExpr{DescriptorInquiry{ - base, DescriptorInquiry::Field::LowerBound, dimension}}; + return ExtentExpr{DescriptorInquiry{NamedEntity{symbol0}, + DescriptorInquiry::Field::LowerBound, dimension_}}; } else { break; } } } + } else if (const auto *assoc{ + symbol.detailsIf()}) { + return (*this)(assoc->expr()); } - // When we don't know that we don't know the lower bound at compilation - // time, then we do know it, and it's one. (See LBOUND, 16.9.109). - return ExtentExpr{1}; + return Default(); +} + +auto GetLowerBoundHelper::operator()(const Component &component) -> Result { + if (component.base().Rank() == 0) { + const Symbol &symbol{component.GetLastSymbol().GetUltimate()}; + if (const auto *details{ + symbol.detailsIf()}) { + int j{0}; + for (const auto &shapeSpec : details->shape()) { + if (j++ == dimension_) { + if (const auto &bound{shapeSpec.lbound().GetExplicit()}) { + return Fold(context_, common::Clone(*bound)); + } else if (semantics::IsDescriptor(symbol)) { + return ExtentExpr{ + DescriptorInquiry{NamedEntity{common::Clone(component)}, + DescriptorInquiry::Field::LowerBound, dimension_}}; + } else { + break; + } + } + } + } + } + return Default(); +} + +ExtentExpr GetLowerBound( + FoldingContext &context, const NamedEntity &base, int dimension) { + return GetLowerBoundHelper{context, dimension}(base); } Shape GetLowerBounds(FoldingContext &context, const NamedEntity &base) { - const Symbol &symbol{ResolveAssociations(base.GetLastSymbol())}; Shape result; - if (const auto *details{symbol.detailsIf()}) { - int dim{0}; - for (const auto &shapeSpec : details->shape()) { - if (const auto &bound{shapeSpec.lbound().GetExplicit()}) { - result.emplace_back(Fold(context, common::Clone(*bound))); - } else if (semantics::IsDescriptor(symbol)) { - result.emplace_back(ExtentExpr{DescriptorInquiry{ - base, DescriptorInquiry::Field::LowerBound, dim}}); - } else { - result.emplace_back(std::nullopt); - } - ++dim; - } - } else { - int rank{base.Rank()}; - for (int dim{0}; dim < rank; ++dim) { - result.emplace_back(ExtentExpr{1}); - } + int rank{base.Rank()}; + for (int dim{0}; dim < rank; ++dim) { + result.emplace_back(GetLowerBound(context, base, dim)); } - CHECK(GetRank(result) == symbol.Rank()); return result; } @@ -327,7 +359,9 @@ MaybeExtentExpr GetUpperBound( symbol.detailsIf()}) { if (auto shape{GetShape(context, assoc->expr())}) { if (dimension < static_cast(shape->size())) { - return std::move(shape->at(dimension)); + return ComputeUpperBound(context, + GetLowerBound(context, base, dimension), + std::move(shape->at(dimension))); } } }