Skip to content

Commit

Permalink
[flang] Fix crash from fuzzy test. (llvm#122364)
Browse files Browse the repository at this point in the history
  • Loading branch information
klausler authored and paulhuggett committed Jan 16, 2025
1 parent 4a06ed1 commit b2e7a4a
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 21 deletions.
8 changes: 6 additions & 2 deletions flang/include/flang/Evaluate/shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,12 @@ class GetShapeHelper
}
template <typename D, typename R, typename LO, typename RO>
Result operator()(const Operation<D, R, LO, RO> &operation) const {
if (operation.right().Rank() > 0) {
return (*this)(operation.right());
if (int rr{operation.right().Rank()}; rr > 0) {
if (int lr{operation.left().Rank()}; lr == 0 || lr == rr) {
return (*this)(operation.right());
} else {
return std::nullopt;
}
} else {
return (*this)(operation.left());
}
Expand Down
6 changes: 5 additions & 1 deletion flang/lib/Evaluate/fold-implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -1643,8 +1643,12 @@ auto ApplyElementwise(FoldingContext &context,
-> std::optional<Expr<RESULT>> {
auto resultLength{ComputeResultLength(operation)};
auto &leftExpr{operation.left()};
leftExpr = Fold(context, std::move(leftExpr));
auto &rightExpr{operation.right()};
if (leftExpr.Rank() != rightExpr.Rank() && leftExpr.Rank() != 0 &&
rightExpr.Rank() != 0) {
return std::nullopt; // error recovery
}
leftExpr = Fold(context, std::move(leftExpr));
rightExpr = Fold(context, std::move(rightExpr));
if (leftExpr.Rank() > 0) {
if (std::optional<Shape> leftShape{GetShape(context, leftExpr)}) {
Expand Down
52 changes: 34 additions & 18 deletions flang/lib/Evaluate/shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ class GetLowerBoundHelper
if (dimension_ < rank) {
const semantics::ShapeSpec &shapeSpec{object->shape()[dimension_]};
if (shapeSpec.lbound().isExplicit()) {
if (const auto &lbound{shapeSpec.lbound().GetExplicit()}) {
if (const auto &lbound{shapeSpec.lbound().GetExplicit()};
lbound && lbound->Rank() == 0) {
if constexpr (LBOUND_SEMANTICS) {
bool ok{false};
auto lbValue{ToInt64(*lbound)};
Expand All @@ -266,7 +267,8 @@ class GetLowerBoundHelper
} else if (lbValue.value_or(0) == 1) {
// Lower bound is 1, regardless of extent
ok = true;
} else if (const auto &ubound{shapeSpec.ubound().GetExplicit()}) {
} else if (const auto &ubound{shapeSpec.ubound().GetExplicit()};
ubound && ubound->Rank() == 0) {
// If we can't prove that the dimension is nonempty,
// we must be conservative.
// TODO: simple symbolic math in expression rewriting to
Expand Down Expand Up @@ -459,7 +461,7 @@ static MaybeExtentExpr GetNonNegativeExtent(
} else {
return ExtentExpr{*uval - *lval + 1};
}
} else if (lbound && ubound &&
} else if (lbound && ubound && lbound->Rank() == 0 && ubound->Rank() == 0 &&
(!invariantOnly ||
(IsScopeInvariantExpr(*lbound) && IsScopeInvariantExpr(*ubound)))) {
// Apply effective IDIM (MAX calculation with 0) so thet the
Expand Down Expand Up @@ -608,7 +610,8 @@ MaybeExtentExpr GetRawUpperBound(
int rank{details->shape().Rank()};
if (dimension < rank) {
const auto &bound{details->shape()[dimension].ubound().GetExplicit()};
if (bound && (!invariantOnly || IsScopeInvariantExpr(*bound))) {
if (bound && bound->Rank() == 0 &&
(!invariantOnly || IsScopeInvariantExpr(*bound))) {
return *bound;
} else if (semantics::IsAssumedSizeArray(symbol) &&
dimension + 1 == symbol.Rank()) {
Expand Down Expand Up @@ -640,7 +643,8 @@ MaybeExtentExpr GetRawUpperBound(FoldingContext &context,
static MaybeExtentExpr GetExplicitUBOUND(FoldingContext *context,
const semantics::ShapeSpec &shapeSpec, bool invariantOnly) {
const auto &ubound{shapeSpec.ubound().GetExplicit()};
if (ubound && (!invariantOnly || IsScopeInvariantExpr(*ubound))) {
if (ubound && ubound->Rank() == 0 &&
(!invariantOnly || IsScopeInvariantExpr(*ubound))) {
if (auto extent{GetNonNegativeExtent(shapeSpec, invariantOnly)}) {
if (auto cstExtent{ToInt64(
context ? Fold(*context, std::move(*extent)) : *extent)}) {
Expand Down Expand Up @@ -731,7 +735,8 @@ MaybeExtentExpr GetLCOBOUND(
if (dimension < corank) {
const semantics::ShapeSpec &shapeSpec{object->coshape()[dimension]};
if (const auto &lcobound{shapeSpec.lbound().GetExplicit()}) {
if (!invariantOnly || IsScopeInvariantExpr(*lcobound)) {
if (lcobound->Rank() == 0 &&
(!invariantOnly || IsScopeInvariantExpr(*lcobound))) {
return *lcobound;
}
}
Expand All @@ -748,7 +753,8 @@ MaybeExtentExpr GetUCOBOUND(
if (dimension < corank - 1) {
const semantics::ShapeSpec &shapeSpec{object->coshape()[dimension]};
if (const auto ucobound{shapeSpec.ubound().GetExplicit()}) {
if (!invariantOnly || IsScopeInvariantExpr(*ucobound)) {
if (ucobound->Rank() == 0 &&
(!invariantOnly || IsScopeInvariantExpr(*ucobound))) {
return *ucobound;
}
}
Expand Down Expand Up @@ -822,7 +828,7 @@ auto GetShapeHelper::operator()(const Symbol &symbol) const -> Result {
if (subp.isFunction()) {
auto resultShape{(*this)(subp.result())};
if (resultShape && !useResultSymbolShape_) {
// Ensure the shape is constant. Otherwise, it may be referring
// Ensure the shape is constant. Otherwise, it may be reerring
// to symbols that belong to the function's scope and are
// meaningless on the caller side without the related call
// expression.
Expand Down Expand Up @@ -908,23 +914,33 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
if (auto chars{characteristics::Procedure::FromActuals(
call.proc(), call.arguments(), *context_)}) {
std::size_t j{0};
std::size_t anyArrayArgRank{0};
const ActualArgument *nonOptionalArrayArg{nullptr};
int anyArrayArgRank{0};
for (const auto &arg : call.arguments()) {
if (arg && arg->Rank() > 0 && j < chars->dummyArguments.size()) {
anyArrayArgRank = arg->Rank();
if (!chars->dummyArguments[j].IsOptional()) {
return (*this)(*arg);
if (!anyArrayArgRank) {
anyArrayArgRank = arg->Rank();
} else if (arg->Rank() != anyArrayArgRank) {
return std::nullopt; // error recovery
}
if (!nonOptionalArrayArg &&
!chars->dummyArguments[j].IsOptional()) {
nonOptionalArrayArg = &*arg;
}
}
++j;
}
if (anyArrayArgRank) {
// All dummy array arguments of the procedure are OPTIONAL.
// We cannot take the shape from just any array argument,
// because all of them might be OPTIONAL dummy arguments
// of the caller. Return unknown shape ranked according
// to the last actual array argument.
return Shape(anyArrayArgRank, MaybeExtentExpr{});
if (nonOptionalArrayArg) {
return (*this)(*nonOptionalArrayArg);
} else {
// All dummy array arguments of the procedure are OPTIONAL.
// We cannot take the shape from just any array argument,
// because all of them might be OPTIONAL dummy arguments
// of the caller. Return unknown shape ranked according
// to the last actual array argument.
return Shape(anyArrayArgRank, MaybeExtentExpr{});
}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions flang/test/Semantics/bug122002a.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
! ERROR: Missing initialization for parameter 'n'
! ERROR: Must be a scalar value, but is a rank-1 array
integer, parameter :: n(n)
end
13 changes: 13 additions & 0 deletions flang/test/Semantics/bug122002b.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
SUBROUTINE sub00(a,b,n,m)
complex(2) n,m
! ERROR: Must have INTEGER type, but is COMPLEX(2)
! ERROR: Must have INTEGER type, but is COMPLEX(2)
! ERROR: The type of 'b' has already been implicitly declared
complex(3) a(n,m), b(size((LOG ((x * (a) - a + b / a - a))+1 - x)))
a = a ** n
! ERROR: DO controls should be INTEGER
DO 10 j = 1,m
a = n ** a
10 PRINT *, g
END SUBROUTINE sub00

0 comments on commit b2e7a4a

Please sign in to comment.