Skip to content

Commit 0996b59

Browse files
committed
[flang] Infrastructure improvements in utility routines
* IsArrayElement() needs another option to control whether it should ignore trailing component references. * Add IsObjectPointer(). * Add const Scope& variants of IsFunction() and IsProcedure(). * Make TypeAndShape::Characterize() work with procedure bindings. * Handle CHARACTER length in MeasureSizeInBytes(). * Fine-tune FindExternallyVisibleObject()'s handling of dummy arguments to conform with Fortran 2018: only INTENT(IN) and dummy pointers in pure functions signify; update two tests accordingly. Also: resolve some stylistic inconsistencies and add a missing "const" in the expression traversal template framework. Differential Revision: https://reviews.llvm.org/D95011
1 parent 8dd58a5 commit 0996b59

File tree

8 files changed

+119
-22
lines changed

8 files changed

+119
-22
lines changed

flang/include/flang/Evaluate/call.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,18 @@ class ActualArgument {
111111
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
112112

113113
std::optional<parser::CharBlock> keyword() const { return keyword_; }
114-
void set_keyword(parser::CharBlock x) { keyword_ = x; }
114+
ActualArgument &set_keyword(parser::CharBlock x) {
115+
keyword_ = x;
116+
return *this;
117+
}
115118
bool isAlternateReturn() const {
116119
return std::holds_alternative<common::Label>(u_);
117120
}
118121
bool isPassedObject() const { return isPassedObject_; }
119-
void set_isPassedObject(bool yes = true) { isPassedObject_ = yes; }
122+
ActualArgument &set_isPassedObject(bool yes = true) {
123+
isPassedObject_ = yes;
124+
return *this;
125+
}
120126

121127
bool Matches(const characteristics::DummyArgument &) const;
122128
common::Intent dummyIntent() const { return dummyIntent_; }

flang/include/flang/Evaluate/tools.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,14 @@ std::optional<DataRef> ExtractSubstringBase(const Substring &);
235235

236236
// Predicate: is an expression is an array element reference?
237237
template <typename T>
238-
bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = false) {
238+
bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
239+
bool skipComponents = false) {
239240
if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
240241
const DataRef *ref{&*dataRef};
241-
while (const Component * component{std::get_if<Component>(&ref->u)}) {
242-
ref = &component->base();
242+
if (skipComponents) {
243+
while (const Component * component{std::get_if<Component>(&ref->u)}) {
244+
ref = &component->base();
245+
}
243246
}
244247
if (const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
245248
return !coarrayRef->subscript().empty();
@@ -789,6 +792,7 @@ bool IsProcedure(const Expr<SomeType> &);
789792
bool IsFunction(const Expr<SomeType> &);
790793
bool IsProcedurePointer(const Expr<SomeType> &);
791794
bool IsNullPointer(const Expr<SomeType> &);
795+
bool IsObjectPointer(const Expr<SomeType> &, FoldingContext &);
792796

793797
// Extracts the chain of symbols from a designator, which has perhaps been
794798
// wrapped in an Expr<>, removing all of the (co)subscripts. The
@@ -913,12 +917,13 @@ class Scope;
913917
// These functions are used in Evaluate so they are defined here rather than in
914918
// Semantics to avoid a link-time dependency on Semantics.
915919
// All of these apply GetUltimate() or ResolveAssociations() to their arguments.
916-
917920
bool IsVariableName(const Symbol &);
918921
bool IsPureProcedure(const Symbol &);
919922
bool IsPureProcedure(const Scope &);
920923
bool IsFunction(const Symbol &);
924+
bool IsFunction(const Scope &);
921925
bool IsProcedure(const Symbol &);
926+
bool IsProcedure(const Scope &);
922927
bool IsProcedurePointer(const Symbol &);
923928
bool IsSaved(const Symbol &); // saved implicitly or explicitly
924929
bool IsDummy(const Symbol &);

flang/include/flang/Evaluate/traverse.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ template <typename Visitor, typename Result> class Traverse {
5050
Result operator()(const common::Indirection<A, C> &x) const {
5151
return visitor_(x.value());
5252
}
53-
template <typename A> Result operator()(SymbolRef x) const {
53+
template <typename A> Result operator()(const SymbolRef x) const {
5454
return visitor_(*x);
5555
}
5656
template <typename A> Result operator()(const std::unique_ptr<A> &x) const {

flang/lib/Evaluate/characteristics.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ std::optional<TypeAndShape> TypeAndShape::Characterize(
100100
[&](const semantics::AssocEntityDetails &assoc) {
101101
return Characterize(assoc, context);
102102
},
103+
[&](const semantics::ProcBindingDetails &binding) {
104+
return Characterize(binding.symbol(), context);
105+
},
103106
[](const auto &) { return std::optional<TypeAndShape>{}; },
104107
},
105108
// GetUltimate() used here, not ResolveAssociations(), because
@@ -178,6 +181,12 @@ std::optional<Expr<SubscriptInteger>> TypeAndShape::MeasureSizeInBytes(
178181
if (auto elements{GetSize(Shape{shape_})}) {
179182
// Sizes of arrays (even with single elements) are multiples of
180183
// their alignments.
184+
if (LEN_) {
185+
CHECK(type_.category() == TypeCategory::Character);
186+
return Fold(foldingContext,
187+
std::move(*elements) * Expr<SubscriptInteger>{type_.kind()} *
188+
Expr<SubscriptInteger>{*LEN_});
189+
}
181190
if (auto elementBytes{
182191
type_.MeasureSizeInBytes(foldingContext, GetRank(shape_) > 0)}) {
183192
return Fold(

flang/lib/Evaluate/tools.cpp

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ auto IsVariableHelper::operator()(const Substring &x) const -> Result {
6666
auto IsVariableHelper::operator()(const ProcedureDesignator &x) const
6767
-> Result {
6868
const Symbol *symbol{x.GetSymbol()};
69-
return symbol && symbol->attrs().test(semantics::Attr::POINTER);
69+
return symbol && IsPointer(*symbol);
7070
}
7171

7272
// Conversions of COMPLEX component expressions to REAL.
@@ -696,6 +696,40 @@ bool IsProcedurePointer(const Expr<SomeType> &expr) {
696696
expr.u);
697697
}
698698

699+
template <typename A> inline const ProcedureRef *UnwrapProcedureRef(const A &) {
700+
return nullptr;
701+
}
702+
703+
template <typename T>
704+
inline const ProcedureRef *UnwrapProcedureRef(const FunctionRef<T> &func) {
705+
return &func;
706+
}
707+
708+
template <typename T>
709+
inline const ProcedureRef *UnwrapProcedureRef(const Expr<T> &expr) {
710+
return std::visit(
711+
[](const auto &x) { return UnwrapProcedureRef(x); }, expr.u);
712+
}
713+
714+
// IsObjectPointer()
715+
bool IsObjectPointer(const Expr<SomeType> &expr, FoldingContext &context) {
716+
if (IsNullPointer(expr)) {
717+
return true;
718+
} else if (IsProcedurePointer(expr)) {
719+
return false;
720+
} else if (const auto *procRef{UnwrapProcedureRef(expr)}) {
721+
auto proc{
722+
characteristics::Procedure::Characterize(procRef->proc(), context)};
723+
return proc && proc->functionResult &&
724+
proc->functionResult->attrs.test(
725+
characteristics::FunctionResult::Attr::Pointer);
726+
} else if (const Symbol * symbol{GetLastSymbol(expr)}) {
727+
return IsPointer(symbol->GetUltimate());
728+
} else {
729+
return false;
730+
}
731+
}
732+
699733
// IsNullPointer()
700734
struct IsNullPointerHelper : public AllTraverse<IsNullPointerHelper, false> {
701735
using Base = AllTraverse<IsNullPointerHelper, false>;
@@ -1026,6 +1060,11 @@ bool IsFunction(const Symbol &symbol) {
10261060
symbol.GetUltimate().details());
10271061
}
10281062

1063+
bool IsFunction(const Scope &scope) {
1064+
const Symbol *symbol{scope.GetSymbol()};
1065+
return symbol && IsFunction(*symbol);
1066+
}
1067+
10291068
bool IsProcedure(const Symbol &symbol) {
10301069
return std::visit(common::visitors{
10311070
[](const SubprogramDetails &) { return true; },
@@ -1038,8 +1077,14 @@ bool IsProcedure(const Symbol &symbol) {
10381077
symbol.GetUltimate().details());
10391078
}
10401079

1041-
const Symbol *FindCommonBlockContaining(const Symbol &object) {
1042-
const auto *details{object.detailsIf<ObjectEntityDetails>()};
1080+
bool IsProcedure(const Scope &scope) {
1081+
const Symbol *symbol{scope.GetSymbol()};
1082+
return symbol && IsProcedure(*symbol);
1083+
}
1084+
1085+
const Symbol *FindCommonBlockContaining(const Symbol &original) {
1086+
const Symbol &root{GetAssociationRoot(original)};
1087+
const auto *details{root.detailsIf<ObjectEntityDetails>()};
10431088
return details ? details->commonBlock() : nullptr;
10441089
}
10451090

flang/lib/Semantics/tools.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -330,15 +330,22 @@ const Symbol *FindExternallyVisibleObject(
330330
const Symbol &object, const Scope &scope) {
331331
// TODO: Storage association with any object for which this predicate holds,
332332
// once EQUIVALENCE is supported.
333-
if (IsUseAssociated(object, scope) || IsHostAssociated(object, scope) ||
334-
(IsPureProcedure(scope) && IsPointerDummy(object)) ||
335-
(IsIntentIn(object) && IsDummy(object))) {
333+
const Symbol &ultimate{GetAssociationRoot(object)};
334+
if (IsDummy(ultimate)) {
335+
if (IsIntentIn(ultimate)) {
336+
return &ultimate;
337+
}
338+
if (IsPointer(ultimate) && IsPureProcedure(ultimate.owner()) &&
339+
IsFunction(ultimate.owner())) {
340+
return &ultimate;
341+
}
342+
} else if (&GetProgramUnitContaining(ultimate) !=
343+
&GetProgramUnitContaining(scope)) {
336344
return &object;
337-
} else if (const Symbol * block{FindCommonBlockContaining(object)}) {
345+
} else if (const Symbol * block{FindCommonBlockContaining(ultimate)}) {
338346
return block;
339-
} else {
340-
return nullptr;
341347
}
348+
return nullptr;
342349
}
343350

344351
bool ExprHasTypeCategory(

flang/test/Semantics/structconst03.f90

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ pure subroutine ps1(dummy1, dummy2, dummy3, dummy4)
7171
!ERROR: Externally visible object 'dummy1' may not be associated with pointer component 'pt1' in a pure procedure
7272
x1 = t1(0)(dummy1)
7373
x1 = t1(0)(dummy2)
74-
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
7574
x1 = t1(0)(dummy3)
7675
! TODO when semantics handles coindexing:
7776
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
@@ -106,9 +105,7 @@ pure subroutine subr(dummy1a, dummy2a, dummy3a, dummy4a)
106105
!ERROR: Externally visible object 'dummy1a' may not be associated with pointer component 'pt1' in a pure procedure
107106
x1a = t1(0)(dummy1a)
108107
x1a = t1(0)(dummy2a)
109-
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
110108
x1a = t1(0)(dummy3)
111-
!ERROR: Externally visible object 'dummy3a' may not be associated with pointer component 'pt1' in a pure procedure
112109
x1a = t1(0)(dummy3a)
113110
! TODO when semantics handles coindexing:
114111
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
@@ -123,6 +120,22 @@ pure subroutine subr(dummy1a, dummy2a, dummy3a, dummy4a)
123120
end subroutine subr
124121
end subroutine
125122

123+
pure integer function pf1(dummy3)
124+
real, pointer :: dummy3
125+
type(t1(0)) :: x1
126+
pf1 = 0
127+
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
128+
x1 = t1(0)(dummy3)
129+
contains
130+
pure subroutine subr(dummy3a)
131+
real, pointer :: dummy3a
132+
type(t1(0)) :: x1a
133+
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
134+
x1a = t1(0)(dummy3)
135+
x1a = t1(0)(dummy3a)
136+
end subroutine
137+
end function
138+
126139
impure real function ipf1(dummy1, dummy2, dummy3, dummy4)
127140
real, target :: local1
128141
type(t1(0)) :: x1

flang/test/Semantics/structconst04.f90

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ pure subroutine ps1(dummy1, dummy2, dummy3, dummy4)
6666
!ERROR: Externally visible object 'dummy1' may not be associated with pointer component 'pt1' in a pure procedure
6767
x1 = t1(dummy1)
6868
x1 = t1(dummy2)
69-
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
7069
x1 = t1(dummy3)
7170
! TODO when semantics handles coindexing:
7271
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
@@ -101,9 +100,7 @@ pure subroutine subr(dummy1a, dummy2a, dummy3a, dummy4a)
101100
!ERROR: Externally visible object 'dummy1a' may not be associated with pointer component 'pt1' in a pure procedure
102101
x1a = t1(dummy1a)
103102
x1a = t1(dummy2a)
104-
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
105103
x1a = t1(dummy3)
106-
!ERROR: Externally visible object 'dummy3a' may not be associated with pointer component 'pt1' in a pure procedure
107104
x1a = t1(dummy3a)
108105
! TODO when semantics handles coindexing:
109106
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
@@ -118,6 +115,21 @@ pure subroutine subr(dummy1a, dummy2a, dummy3a, dummy4a)
118115
end subroutine subr
119116
end subroutine
120117

118+
pure integer function pf1(dummy3)
119+
real, pointer :: dummy3
120+
type(t1) :: x1
121+
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
122+
x1 = t1(dummy3)
123+
contains
124+
pure subroutine subr(dummy3a)
125+
real, pointer :: dummy3a
126+
type(t1) :: x1a
127+
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
128+
x1a = t1(dummy3)
129+
x1a = t1(dummy3a)
130+
end subroutine
131+
end function
132+
121133
impure real function ipf1(dummy1, dummy2, dummy3, dummy4)
122134
real, target :: local1
123135
type(t1) :: x1

0 commit comments

Comments
 (0)