Skip to content

Commit 38763be

Browse files
authored
[flang] Do not traverse selectors in FindImpureCall and HasVectorSubscript (#84041)
In presence of symbols with AssocEntityDetails in an expression, `Traverse`, `AnyTraverse`, `AllTraverse`, and `SetTraverse` automatically visit the selector expression or variable. This is most often the desired behavior but can be surprising, and was not correct for FindImpureCall and HasVectorSubscript. Add a default template option to flag the behavior to someone willing to use the Traverse helper for a new utility, and set this template to false for FindImpureCall and HasVectorSubscript.
1 parent 8406f80 commit 38763be

File tree

4 files changed

+34
-14
lines changed

4 files changed

+34
-14
lines changed

flang/include/flang/Evaluate/traverse.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@
4545
#include <type_traits>
4646

4747
namespace Fortran::evaluate {
48-
template <typename Visitor, typename Result> class Traverse {
48+
template <typename Visitor, typename Result,
49+
bool TraverseAssocEntityDetails = true>
50+
class Traverse {
4951
public:
5052
explicit Traverse(Visitor &v) : visitor_{v} {}
5153

@@ -108,12 +110,13 @@ template <typename Visitor, typename Result> class Traverse {
108110
}
109111
Result operator()(const Symbol &symbol) const {
110112
const Symbol &ultimate{symbol.GetUltimate()};
111-
if (const auto *assoc{
112-
ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
113-
return visitor_(assoc->expr());
114-
} else {
115-
return visitor_.Default();
113+
if constexpr (TraverseAssocEntityDetails) {
114+
if (const auto *assoc{
115+
ultimate.detailsIf<semantics::AssocEntityDetails>()}) {
116+
return visitor_(assoc->expr());
117+
}
116118
}
119+
return visitor_.Default();
117120
}
118121
Result operator()(const StaticDataObject &) const {
119122
return visitor_.Default();
@@ -284,7 +287,8 @@ template <typename Visitor, typename Result> class Traverse {
284287
// For validity checks across an expression: if any operator() result is
285288
// false, so is the overall result.
286289
template <typename Visitor, bool DefaultValue,
287-
typename Base = Traverse<Visitor, bool>>
290+
bool TraverseAssocEntityDetails = true,
291+
typename Base = Traverse<Visitor, bool, TraverseAssocEntityDetails>>
288292
struct AllTraverse : public Base {
289293
explicit AllTraverse(Visitor &v) : Base{v} {}
290294
using Base::operator();
@@ -296,7 +300,8 @@ struct AllTraverse : public Base {
296300
// is truthful is the final result. Works for Booleans, pointers,
297301
// and std::optional<>.
298302
template <typename Visitor, typename Result = bool,
299-
typename Base = Traverse<Visitor, Result>>
303+
bool TraverseAssocEntityDetails = true,
304+
typename Base = Traverse<Visitor, Result, TraverseAssocEntityDetails>>
300305
class AnyTraverse : public Base {
301306
public:
302307
explicit AnyTraverse(Visitor &v) : Base{v} {}
@@ -315,7 +320,8 @@ class AnyTraverse : public Base {
315320
};
316321

317322
template <typename Visitor, typename Set,
318-
typename Base = Traverse<Visitor, Set>>
323+
bool TraverseAssocEntityDetails = true,
324+
typename Base = Traverse<Visitor, Set, TraverseAssocEntityDetails>>
319325
struct SetTraverse : public Base {
320326
explicit SetTraverse(Visitor &v) : Base{v} {}
321327
using Base::operator();

flang/lib/Evaluate/tools.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -995,8 +995,10 @@ template semantics::UnorderedSymbolSet CollectSymbols(
995995
const Expr<SubscriptInteger> &);
996996

997997
// HasVectorSubscript()
998-
struct HasVectorSubscriptHelper : public AnyTraverse<HasVectorSubscriptHelper> {
999-
using Base = AnyTraverse<HasVectorSubscriptHelper>;
998+
struct HasVectorSubscriptHelper
999+
: public AnyTraverse<HasVectorSubscriptHelper, bool,
1000+
/*TraverseAssocEntityDetails=*/false> {
1001+
using Base = AnyTraverse<HasVectorSubscriptHelper, bool, false>;
10001002
HasVectorSubscriptHelper() : Base{*this} {}
10011003
using Base::operator();
10021004
bool operator()(const Subscript &ss) const {
@@ -1045,9 +1047,10 @@ parser::Message *AttachDeclaration(
10451047
}
10461048

10471049
class FindImpureCallHelper
1048-
: public AnyTraverse<FindImpureCallHelper, std::optional<std::string>> {
1050+
: public AnyTraverse<FindImpureCallHelper, std::optional<std::string>,
1051+
/*TraverseAssocEntityDetails=*/false> {
10491052
using Result = std::optional<std::string>;
1050-
using Base = AnyTraverse<FindImpureCallHelper, Result>;
1053+
using Base = AnyTraverse<FindImpureCallHelper, Result, false>;
10511054

10521055
public:
10531056
explicit FindImpureCallHelper(FoldingContext &c) : Base{*this}, context_{c} {}

flang/test/Semantics/forall01.f90

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,14 @@ subroutine forall7(x)
135135
end forall
136136
end select
137137
end subroutine
138+
139+
subroutine forall8(x)
140+
real :: x(10)
141+
real, external :: foo
142+
!ERROR: Impure procedure 'foo' may not be referenced in a FORALL
143+
forall(i=1:10) x(i) = foo() + i
144+
!OK
145+
associate(y => foo())
146+
forall (i=1:10) x(i) = y + i
147+
end associate
148+
end subroutine

flang/test/Semantics/selecttype03.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
b%i = 1 !VDC
6666
type is (t2)
6767
!ERROR: Actual argument associated with INTENT(IN OUT) dummy argument 'z=' is not definable
68-
!BECAUSE: Variable 'b' has a vector subscript
68+
!BECAUSE: Construct association 'b' has a vector subscript
6969
call sub_with_in_and_inout_param_vector(b,b) !VDC
7070
end select
7171
select type(b => foo(1) )

0 commit comments

Comments
 (0)