diff --git a/flang/lib/Evaluate/fold-integer.cpp b/flang/lib/Evaluate/fold-integer.cpp --- a/flang/lib/Evaluate/fold-integer.cpp +++ b/flang/lib/Evaluate/fold-integer.cpp @@ -7,9 +7,44 @@ //===----------------------------------------------------------------------===// #include "fold-implementation.h" +#include "flang/Evaluate/check-expression.h" namespace Fortran::evaluate { +// Class to retrieve the constant lower bound of an expression which is an +// array that devolves to a type of Constant +class GetConstantArrayLboundHelper { +public: + GetConstantArrayLboundHelper(ConstantSubscript dim) : dim_{dim} {} + + template ConstantSubscript GetLbound(const T &) { + // The method is needed for template expansion, but we should never get + // here in practice. + CHECK(false); + return 0; + } + + template ConstantSubscript GetLbound(const Constant &x) { + // Return the lower bound + return x.lbounds()[dim_]; + } + + template ConstantSubscript GetLbound(const Parentheses &x) { + // Strip off the parentheses + return GetLbound(x.left()); + } + + template ConstantSubscript GetLbound(const Expr &x) { + // recurse through Expr'a until we hit a constant + return std::visit([&](const auto &inner) { return GetLbound(inner); }, + // [&](const auto &) { return 0; }, + x.u); + } + +private: + ConstantSubscript dim_; +}; + template Expr> LBOUND(FoldingContext &context, FunctionRef> &&funcRef) { @@ -51,6 +86,9 @@ lowerBoundsAreOne = symbol.Rank() == 0; // LBOUND(array%component) } } + if (IsActuallyConstant(*array)) { + return Expr{GetConstantArrayLboundHelper{*dim}.GetLbound(*array)}; + } if (lowerBoundsAreOne) { if (dim) { return Expr{1}; diff --git a/flang/test/Evaluate/folding16.f90 b/flang/test/Evaluate/folding16.f90 --- a/flang/test/Evaluate/folding16.f90 +++ b/flang/test/Evaluate/folding16.f90 @@ -7,10 +7,8 @@ integer, parameter :: c(-1:1) = [33, 22, 11] integer, parameter :: d(1:3) = [33, 22, 11] integer, parameter :: e(-2:0) = ([33, 22, 11]) - ! The following test is commented out because constant folding for "lbound" - ! is currently broken - !logical, parameter :: test_1 = lbound(a,1)==-1 .and. lbound(b,1)==-1 .and. & - ! lbound(log(a),1)==1 .and. all(b==0) + logical, parameter :: test_1 = lbound((a),1)==-1 .and. lbound(b,1)==-1 .and. & + lbound(log(a),1)==1 .and. all(b==0) logical, parameter :: test_2 = all(c .eq. d) logical, parameter :: test_3 = all(c .eq. e) logical, parameter :: test_4 = all(d .eq. e)