[flang] Preserve component array lower bounds in folding

When a component array of a named constant is extracted as
a constant value, ensure that the lower bounds of the array
are properly acquired from the declaration of the component.

Differential Revision: https://reviews.llvm.org/D134499
This commit is contained in:
Peter Klausler 2022-09-21 12:22:18 -07:00
parent 0d58a8cd49
commit 3bbb2c2d99
3 changed files with 37 additions and 26 deletions

View File

@ -1109,6 +1109,33 @@ std::optional<Expr<SomeType>> DataConstantConversionExtension(
std::optional<Expr<SomeType>> HollerithToBOZ(
FoldingContext &, const Expr<SomeType> &, const DynamicType &);
// Set explicit lower bounds on a constant array.
class ArrayConstantBoundChanger {
public:
explicit ArrayConstantBoundChanger(ConstantSubscripts &&lbounds)
: lbounds_{std::move(lbounds)} {}
template <typename A> A ChangeLbounds(A &&x) const {
return std::move(x); // default case
}
template <typename T> Constant<T> ChangeLbounds(Constant<T> &&x) {
x.set_lbounds(std::move(lbounds_));
return std::move(x);
}
template <typename T> Expr<T> ChangeLbounds(Parentheses<T> &&x) {
return ChangeLbounds(
std::move(x.left())); // Constant<> can be parenthesized
}
template <typename T> Expr<T> ChangeLbounds(Expr<T> &&x) {
return common::visit(
[&](auto &&x) { return Expr<T>{ChangeLbounds(std::move(x))}; },
std::move(x.u)); // recurse until we hit a constant
}
private:
ConstantSubscripts &&lbounds_;
};
} // namespace Fortran::evaluate
namespace Fortran::semantics {

View File

@ -9,6 +9,7 @@
#include "flang/Evaluate/check-expression.h"
#include "flang/Evaluate/characteristics.h"
#include "flang/Evaluate/intrinsics.h"
#include "flang/Evaluate/tools.h"
#include "flang/Evaluate/traverse.h"
#include "flang/Evaluate/type.h"
#include "flang/Semantics/symbol.h"
@ -363,32 +364,6 @@ bool IsInitialProcedureTarget(const Expr<SomeType> &expr) {
}
}
class ArrayConstantBoundChanger {
public:
ArrayConstantBoundChanger(ConstantSubscripts &&lbounds)
: lbounds_{std::move(lbounds)} {}
template <typename A> A ChangeLbounds(A &&x) const {
return std::move(x); // default case
}
template <typename T> Constant<T> ChangeLbounds(Constant<T> &&x) {
x.set_lbounds(std::move(lbounds_));
return std::move(x);
}
template <typename T> Expr<T> ChangeLbounds(Parentheses<T> &&x) {
return ChangeLbounds(
std::move(x.left())); // Constant<> can be parenthesized
}
template <typename T> Expr<T> ChangeLbounds(Expr<T> &&x) {
return common::visit(
[&](auto &&x) { return Expr<T>{ChangeLbounds(std::move(x))}; },
std::move(x.u)); // recurse until we hit a constant
}
private:
ConstantSubscripts &&lbounds_;
};
// Converts, folds, and then checks type, rank, and shape of an
// initialization expression for a named constant, a non-pointer
// variable static initialization, a component default initializer,

View File

@ -10,6 +10,7 @@
#include "fold-implementation.h"
#include "flang/Evaluate/characteristics.h"
#include "flang/Evaluate/initial-image.h"
#include "flang/Evaluate/tools.h"
namespace Fortran::evaluate {
@ -92,6 +93,14 @@ Expr<SomeDerived> FoldOperation(
} else {
isConstant &= *valueShape == *componentShape;
}
if (*valueShape == *componentShape) {
if (auto lbounds{AsConstantExtents(
context, GetLBOUNDs(context, NamedEntity{symbol}))}) {
expr =
ArrayConstantBoundChanger{std::move(*lbounds)}.ChangeLbounds(
std::move(expr));
}
}
}
}
}