Skip to content

Commit 2cf982c

Browse files
authored
[flang] Don't duplicate impure function call for UBOUND() (#153648)
Because the per-dimension information in a descriptor holds an extent and a lower bound, but not an upper bound, the calculation of the upper bound sometimes requires that the extent and lower bound be extracted from a descriptor and added together, minus 1. This shouldn't be attempted when the NamedEntity of the descriptor is something that shouldn't be duplicated and used twice; specifically, it shouldn't apply to NamedEntities containing references to impure functions as parts of subscript expressions. Fixes #153031.
1 parent 4823259 commit 2cf982c

File tree

3 files changed

+41
-14
lines changed

3 files changed

+41
-14
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,15 +1144,14 @@ std::optional<std::string> FindImpureCall(
11441144
std::optional<std::string> FindImpureCall(
11451145
FoldingContext &, const ProcedureRef &);
11461146

1147-
// Predicate: is a scalar expression suitable for naive scalar expansion
1148-
// in the flattening of an array expression?
1149-
// TODO: capture such scalar expansions in temporaries, flatten everything
1150-
class UnexpandabilityFindingVisitor
1151-
: public AnyTraverse<UnexpandabilityFindingVisitor> {
1147+
// Predicate: does an expression contain anything that would prevent it from
1148+
// being duplicated so that two instances of it then appear in the same
1149+
// expression?
1150+
class UnsafeToCopyVisitor : public AnyTraverse<UnsafeToCopyVisitor> {
11521151
public:
1153-
using Base = AnyTraverse<UnexpandabilityFindingVisitor>;
1152+
using Base = AnyTraverse<UnsafeToCopyVisitor>;
11541153
using Base::operator();
1155-
explicit UnexpandabilityFindingVisitor(bool admitPureCall)
1154+
explicit UnsafeToCopyVisitor(bool admitPureCall)
11561155
: Base{*this}, admitPureCall_{admitPureCall} {}
11571156
template <typename T> bool operator()(const FunctionRef<T> &procRef) {
11581157
return !admitPureCall_ || !procRef.proc().IsPure();
@@ -1163,14 +1162,22 @@ class UnexpandabilityFindingVisitor
11631162
bool admitPureCall_{false};
11641163
};
11651164

1165+
template <typename A>
1166+
bool IsSafelyCopyable(const A &x, bool admitPureCall = false) {
1167+
return !UnsafeToCopyVisitor{admitPureCall}(x);
1168+
}
1169+
1170+
// Predicate: is a scalar expression suitable for naive scalar expansion
1171+
// in the flattening of an array expression?
1172+
// TODO: capture such scalar expansions in temporaries, flatten everything
11661173
template <typename T>
11671174
bool IsExpandableScalar(const Expr<T> &expr, FoldingContext &context,
11681175
const Shape &shape, bool admitPureCall = false) {
1169-
if (UnexpandabilityFindingVisitor{admitPureCall}(expr)) {
1176+
if (IsSafelyCopyable(expr, admitPureCall)) {
1177+
return true;
1178+
} else {
11701179
auto extents{AsConstantExtents(context, shape)};
11711180
return extents && !HasNegativeExtent(*extents) && GetSize(*extents) == 1;
1172-
} else {
1173-
return true;
11741181
}
11751182
}
11761183

flang/lib/Evaluate/shape.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ MaybeExtentExpr GetRawUpperBound(
623623
} else if (semantics::IsAssumedSizeArray(symbol) &&
624624
dimension + 1 == symbol.Rank()) {
625625
return std::nullopt;
626-
} else {
626+
} else if (IsSafelyCopyable(base, /*admitPureCall=*/true)) {
627627
return ComputeUpperBound(
628628
GetRawLowerBound(base, dimension), GetExtent(base, dimension));
629629
}
@@ -678,9 +678,11 @@ static MaybeExtentExpr GetUBOUND(FoldingContext *context,
678678
} else if (semantics::IsAssumedSizeArray(symbol) &&
679679
dimension + 1 == symbol.Rank()) {
680680
return std::nullopt; // UBOUND() folding replaces with -1
681-
} else if (auto lb{GetLBOUND(base, dimension, invariantOnly)}) {
682-
return ComputeUpperBound(
683-
std::move(*lb), GetExtent(base, dimension, invariantOnly));
681+
} else if (IsSafelyCopyable(base, /*admitPureCall=*/true)) {
682+
if (auto lb{GetLBOUND(base, dimension, invariantOnly)}) {
683+
return ComputeUpperBound(
684+
std::move(*lb), GetExtent(base, dimension, invariantOnly));
685+
}
684686
}
685687
}
686688
} else if (const auto *assoc{

flang/test/Evaluate/bug153031.f90

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
2+
! Ensure that UBOUND() calculation from LBOUND()+SIZE() isn't applied to
3+
! variables containing references to impure functions.
4+
type t
5+
real, allocatable :: a(:)
6+
end type
7+
interface
8+
pure integer function pure(n)
9+
integer, intent(in) :: n
10+
end
11+
end interface
12+
type(t) :: x(10)
13+
allocate(x(1)%a(2))
14+
!CHECK: PRINT *, ubound(x(int(impure(1_4),kind=8))%a,dim=1_4)
15+
print *, ubound(x(impure(1))%a, dim=1)
16+
!CHECK: PRINT *, int(size(x(int(pure(1_4),kind=8))%a,dim=1,kind=8)+lbound(x(int(pure(1_4),kind=8))%a,dim=1,kind=8)-1_8,kind=4)
17+
print *, ubound(x(pure(1))%a, dim=1)
18+
end

0 commit comments

Comments
 (0)