forked from OSchip/llvm-project
[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
This commit is contained in:
parent
8dd58a509c
commit
0996b590aa
|
@ -111,12 +111,18 @@ public:
|
||||||
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
|
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
|
||||||
|
|
||||||
std::optional<parser::CharBlock> keyword() const { return keyword_; }
|
std::optional<parser::CharBlock> keyword() const { return keyword_; }
|
||||||
void set_keyword(parser::CharBlock x) { keyword_ = x; }
|
ActualArgument &set_keyword(parser::CharBlock x) {
|
||||||
|
keyword_ = x;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
bool isAlternateReturn() const {
|
bool isAlternateReturn() const {
|
||||||
return std::holds_alternative<common::Label>(u_);
|
return std::holds_alternative<common::Label>(u_);
|
||||||
}
|
}
|
||||||
bool isPassedObject() const { return isPassedObject_; }
|
bool isPassedObject() const { return isPassedObject_; }
|
||||||
void set_isPassedObject(bool yes = true) { isPassedObject_ = yes; }
|
ActualArgument &set_isPassedObject(bool yes = true) {
|
||||||
|
isPassedObject_ = yes;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool Matches(const characteristics::DummyArgument &) const;
|
bool Matches(const characteristics::DummyArgument &) const;
|
||||||
common::Intent dummyIntent() const { return dummyIntent_; }
|
common::Intent dummyIntent() const { return dummyIntent_; }
|
||||||
|
|
|
@ -235,11 +235,14 @@ std::optional<DataRef> ExtractSubstringBase(const Substring &);
|
||||||
|
|
||||||
// Predicate: is an expression is an array element reference?
|
// Predicate: is an expression is an array element reference?
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = false) {
|
bool IsArrayElement(const Expr<T> &expr, bool intoSubstring = true,
|
||||||
|
bool skipComponents = false) {
|
||||||
if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
|
if (auto dataRef{ExtractDataRef(expr, intoSubstring)}) {
|
||||||
const DataRef *ref{&*dataRef};
|
const DataRef *ref{&*dataRef};
|
||||||
while (const Component * component{std::get_if<Component>(&ref->u)}) {
|
if (skipComponents) {
|
||||||
ref = &component->base();
|
while (const Component * component{std::get_if<Component>(&ref->u)}) {
|
||||||
|
ref = &component->base();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
|
if (const auto *coarrayRef{std::get_if<CoarrayRef>(&ref->u)}) {
|
||||||
return !coarrayRef->subscript().empty();
|
return !coarrayRef->subscript().empty();
|
||||||
|
@ -789,6 +792,7 @@ bool IsProcedure(const Expr<SomeType> &);
|
||||||
bool IsFunction(const Expr<SomeType> &);
|
bool IsFunction(const Expr<SomeType> &);
|
||||||
bool IsProcedurePointer(const Expr<SomeType> &);
|
bool IsProcedurePointer(const Expr<SomeType> &);
|
||||||
bool IsNullPointer(const Expr<SomeType> &);
|
bool IsNullPointer(const Expr<SomeType> &);
|
||||||
|
bool IsObjectPointer(const Expr<SomeType> &, FoldingContext &);
|
||||||
|
|
||||||
// Extracts the chain of symbols from a designator, which has perhaps been
|
// Extracts the chain of symbols from a designator, which has perhaps been
|
||||||
// wrapped in an Expr<>, removing all of the (co)subscripts. The
|
// wrapped in an Expr<>, removing all of the (co)subscripts. The
|
||||||
|
@ -913,12 +917,13 @@ class Scope;
|
||||||
// These functions are used in Evaluate so they are defined here rather than in
|
// These functions are used in Evaluate so they are defined here rather than in
|
||||||
// Semantics to avoid a link-time dependency on Semantics.
|
// Semantics to avoid a link-time dependency on Semantics.
|
||||||
// All of these apply GetUltimate() or ResolveAssociations() to their arguments.
|
// All of these apply GetUltimate() or ResolveAssociations() to their arguments.
|
||||||
|
|
||||||
bool IsVariableName(const Symbol &);
|
bool IsVariableName(const Symbol &);
|
||||||
bool IsPureProcedure(const Symbol &);
|
bool IsPureProcedure(const Symbol &);
|
||||||
bool IsPureProcedure(const Scope &);
|
bool IsPureProcedure(const Scope &);
|
||||||
bool IsFunction(const Symbol &);
|
bool IsFunction(const Symbol &);
|
||||||
|
bool IsFunction(const Scope &);
|
||||||
bool IsProcedure(const Symbol &);
|
bool IsProcedure(const Symbol &);
|
||||||
|
bool IsProcedure(const Scope &);
|
||||||
bool IsProcedurePointer(const Symbol &);
|
bool IsProcedurePointer(const Symbol &);
|
||||||
bool IsSaved(const Symbol &); // saved implicitly or explicitly
|
bool IsSaved(const Symbol &); // saved implicitly or explicitly
|
||||||
bool IsDummy(const Symbol &);
|
bool IsDummy(const Symbol &);
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
Result operator()(const common::Indirection<A, C> &x) const {
|
Result operator()(const common::Indirection<A, C> &x) const {
|
||||||
return visitor_(x.value());
|
return visitor_(x.value());
|
||||||
}
|
}
|
||||||
template <typename A> Result operator()(SymbolRef x) const {
|
template <typename A> Result operator()(const SymbolRef x) const {
|
||||||
return visitor_(*x);
|
return visitor_(*x);
|
||||||
}
|
}
|
||||||
template <typename A> Result operator()(const std::unique_ptr<A> &x) const {
|
template <typename A> Result operator()(const std::unique_ptr<A> &x) const {
|
||||||
|
|
|
@ -100,6 +100,9 @@ std::optional<TypeAndShape> TypeAndShape::Characterize(
|
||||||
[&](const semantics::AssocEntityDetails &assoc) {
|
[&](const semantics::AssocEntityDetails &assoc) {
|
||||||
return Characterize(assoc, context);
|
return Characterize(assoc, context);
|
||||||
},
|
},
|
||||||
|
[&](const semantics::ProcBindingDetails &binding) {
|
||||||
|
return Characterize(binding.symbol(), context);
|
||||||
|
},
|
||||||
[](const auto &) { return std::optional<TypeAndShape>{}; },
|
[](const auto &) { return std::optional<TypeAndShape>{}; },
|
||||||
},
|
},
|
||||||
// GetUltimate() used here, not ResolveAssociations(), because
|
// GetUltimate() used here, not ResolveAssociations(), because
|
||||||
|
@ -178,6 +181,12 @@ std::optional<Expr<SubscriptInteger>> TypeAndShape::MeasureSizeInBytes(
|
||||||
if (auto elements{GetSize(Shape{shape_})}) {
|
if (auto elements{GetSize(Shape{shape_})}) {
|
||||||
// Sizes of arrays (even with single elements) are multiples of
|
// Sizes of arrays (even with single elements) are multiples of
|
||||||
// their alignments.
|
// their alignments.
|
||||||
|
if (LEN_) {
|
||||||
|
CHECK(type_.category() == TypeCategory::Character);
|
||||||
|
return Fold(foldingContext,
|
||||||
|
std::move(*elements) * Expr<SubscriptInteger>{type_.kind()} *
|
||||||
|
Expr<SubscriptInteger>{*LEN_});
|
||||||
|
}
|
||||||
if (auto elementBytes{
|
if (auto elementBytes{
|
||||||
type_.MeasureSizeInBytes(foldingContext, GetRank(shape_) > 0)}) {
|
type_.MeasureSizeInBytes(foldingContext, GetRank(shape_) > 0)}) {
|
||||||
return Fold(
|
return Fold(
|
||||||
|
|
|
@ -66,7 +66,7 @@ auto IsVariableHelper::operator()(const Substring &x) const -> Result {
|
||||||
auto IsVariableHelper::operator()(const ProcedureDesignator &x) const
|
auto IsVariableHelper::operator()(const ProcedureDesignator &x) const
|
||||||
-> Result {
|
-> Result {
|
||||||
const Symbol *symbol{x.GetSymbol()};
|
const Symbol *symbol{x.GetSymbol()};
|
||||||
return symbol && symbol->attrs().test(semantics::Attr::POINTER);
|
return symbol && IsPointer(*symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversions of COMPLEX component expressions to REAL.
|
// Conversions of COMPLEX component expressions to REAL.
|
||||||
|
@ -696,6 +696,40 @@ bool IsProcedurePointer(const Expr<SomeType> &expr) {
|
||||||
expr.u);
|
expr.u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename A> inline const ProcedureRef *UnwrapProcedureRef(const A &) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline const ProcedureRef *UnwrapProcedureRef(const FunctionRef<T> &func) {
|
||||||
|
return &func;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline const ProcedureRef *UnwrapProcedureRef(const Expr<T> &expr) {
|
||||||
|
return std::visit(
|
||||||
|
[](const auto &x) { return UnwrapProcedureRef(x); }, expr.u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsObjectPointer()
|
||||||
|
bool IsObjectPointer(const Expr<SomeType> &expr, FoldingContext &context) {
|
||||||
|
if (IsNullPointer(expr)) {
|
||||||
|
return true;
|
||||||
|
} else if (IsProcedurePointer(expr)) {
|
||||||
|
return false;
|
||||||
|
} else if (const auto *procRef{UnwrapProcedureRef(expr)}) {
|
||||||
|
auto proc{
|
||||||
|
characteristics::Procedure::Characterize(procRef->proc(), context)};
|
||||||
|
return proc && proc->functionResult &&
|
||||||
|
proc->functionResult->attrs.test(
|
||||||
|
characteristics::FunctionResult::Attr::Pointer);
|
||||||
|
} else if (const Symbol * symbol{GetLastSymbol(expr)}) {
|
||||||
|
return IsPointer(symbol->GetUltimate());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IsNullPointer()
|
// IsNullPointer()
|
||||||
struct IsNullPointerHelper : public AllTraverse<IsNullPointerHelper, false> {
|
struct IsNullPointerHelper : public AllTraverse<IsNullPointerHelper, false> {
|
||||||
using Base = AllTraverse<IsNullPointerHelper, false>;
|
using Base = AllTraverse<IsNullPointerHelper, false>;
|
||||||
|
@ -1026,6 +1060,11 @@ bool IsFunction(const Symbol &symbol) {
|
||||||
symbol.GetUltimate().details());
|
symbol.GetUltimate().details());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsFunction(const Scope &scope) {
|
||||||
|
const Symbol *symbol{scope.GetSymbol()};
|
||||||
|
return symbol && IsFunction(*symbol);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsProcedure(const Symbol &symbol) {
|
bool IsProcedure(const Symbol &symbol) {
|
||||||
return std::visit(common::visitors{
|
return std::visit(common::visitors{
|
||||||
[](const SubprogramDetails &) { return true; },
|
[](const SubprogramDetails &) { return true; },
|
||||||
|
@ -1038,8 +1077,14 @@ bool IsProcedure(const Symbol &symbol) {
|
||||||
symbol.GetUltimate().details());
|
symbol.GetUltimate().details());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Symbol *FindCommonBlockContaining(const Symbol &object) {
|
bool IsProcedure(const Scope &scope) {
|
||||||
const auto *details{object.detailsIf<ObjectEntityDetails>()};
|
const Symbol *symbol{scope.GetSymbol()};
|
||||||
|
return symbol && IsProcedure(*symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Symbol *FindCommonBlockContaining(const Symbol &original) {
|
||||||
|
const Symbol &root{GetAssociationRoot(original)};
|
||||||
|
const auto *details{root.detailsIf<ObjectEntityDetails>()};
|
||||||
return details ? details->commonBlock() : nullptr;
|
return details ? details->commonBlock() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -330,15 +330,22 @@ const Symbol *FindExternallyVisibleObject(
|
||||||
const Symbol &object, const Scope &scope) {
|
const Symbol &object, const Scope &scope) {
|
||||||
// TODO: Storage association with any object for which this predicate holds,
|
// TODO: Storage association with any object for which this predicate holds,
|
||||||
// once EQUIVALENCE is supported.
|
// once EQUIVALENCE is supported.
|
||||||
if (IsUseAssociated(object, scope) || IsHostAssociated(object, scope) ||
|
const Symbol &ultimate{GetAssociationRoot(object)};
|
||||||
(IsPureProcedure(scope) && IsPointerDummy(object)) ||
|
if (IsDummy(ultimate)) {
|
||||||
(IsIntentIn(object) && IsDummy(object))) {
|
if (IsIntentIn(ultimate)) {
|
||||||
|
return &ultimate;
|
||||||
|
}
|
||||||
|
if (IsPointer(ultimate) && IsPureProcedure(ultimate.owner()) &&
|
||||||
|
IsFunction(ultimate.owner())) {
|
||||||
|
return &ultimate;
|
||||||
|
}
|
||||||
|
} else if (&GetProgramUnitContaining(ultimate) !=
|
||||||
|
&GetProgramUnitContaining(scope)) {
|
||||||
return &object;
|
return &object;
|
||||||
} else if (const Symbol * block{FindCommonBlockContaining(object)}) {
|
} else if (const Symbol * block{FindCommonBlockContaining(ultimate)}) {
|
||||||
return block;
|
return block;
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprHasTypeCategory(
|
bool ExprHasTypeCategory(
|
||||||
|
|
|
@ -71,7 +71,6 @@ module module1
|
||||||
!ERROR: Externally visible object 'dummy1' may not be associated with pointer component 'pt1' in a pure procedure
|
!ERROR: Externally visible object 'dummy1' may not be associated with pointer component 'pt1' in a pure procedure
|
||||||
x1 = t1(0)(dummy1)
|
x1 = t1(0)(dummy1)
|
||||||
x1 = t1(0)(dummy2)
|
x1 = t1(0)(dummy2)
|
||||||
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
|
|
||||||
x1 = t1(0)(dummy3)
|
x1 = t1(0)(dummy3)
|
||||||
! TODO when semantics handles coindexing:
|
! TODO when semantics handles coindexing:
|
||||||
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
|
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
|
||||||
|
@ -106,9 +105,7 @@ module module1
|
||||||
!ERROR: Externally visible object 'dummy1a' may not be associated with pointer component 'pt1' in a pure procedure
|
!ERROR: Externally visible object 'dummy1a' may not be associated with pointer component 'pt1' in a pure procedure
|
||||||
x1a = t1(0)(dummy1a)
|
x1a = t1(0)(dummy1a)
|
||||||
x1a = t1(0)(dummy2a)
|
x1a = t1(0)(dummy2a)
|
||||||
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
|
|
||||||
x1a = t1(0)(dummy3)
|
x1a = t1(0)(dummy3)
|
||||||
!ERROR: Externally visible object 'dummy3a' may not be associated with pointer component 'pt1' in a pure procedure
|
|
||||||
x1a = t1(0)(dummy3a)
|
x1a = t1(0)(dummy3a)
|
||||||
! TODO when semantics handles coindexing:
|
! TODO when semantics handles coindexing:
|
||||||
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
|
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
|
||||||
|
@ -123,6 +120,22 @@ module module1
|
||||||
end subroutine subr
|
end subroutine subr
|
||||||
end subroutine
|
end subroutine
|
||||||
|
|
||||||
|
pure integer function pf1(dummy3)
|
||||||
|
real, pointer :: dummy3
|
||||||
|
type(t1(0)) :: x1
|
||||||
|
pf1 = 0
|
||||||
|
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
|
||||||
|
x1 = t1(0)(dummy3)
|
||||||
|
contains
|
||||||
|
pure subroutine subr(dummy3a)
|
||||||
|
real, pointer :: dummy3a
|
||||||
|
type(t1(0)) :: x1a
|
||||||
|
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
|
||||||
|
x1a = t1(0)(dummy3)
|
||||||
|
x1a = t1(0)(dummy3a)
|
||||||
|
end subroutine
|
||||||
|
end function
|
||||||
|
|
||||||
impure real function ipf1(dummy1, dummy2, dummy3, dummy4)
|
impure real function ipf1(dummy1, dummy2, dummy3, dummy4)
|
||||||
real, target :: local1
|
real, target :: local1
|
||||||
type(t1(0)) :: x1
|
type(t1(0)) :: x1
|
||||||
|
|
|
@ -66,7 +66,6 @@ module module1
|
||||||
!ERROR: Externally visible object 'dummy1' may not be associated with pointer component 'pt1' in a pure procedure
|
!ERROR: Externally visible object 'dummy1' may not be associated with pointer component 'pt1' in a pure procedure
|
||||||
x1 = t1(dummy1)
|
x1 = t1(dummy1)
|
||||||
x1 = t1(dummy2)
|
x1 = t1(dummy2)
|
||||||
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
|
|
||||||
x1 = t1(dummy3)
|
x1 = t1(dummy3)
|
||||||
! TODO when semantics handles coindexing:
|
! TODO when semantics handles coindexing:
|
||||||
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
|
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
|
||||||
|
@ -101,9 +100,7 @@ module module1
|
||||||
!ERROR: Externally visible object 'dummy1a' may not be associated with pointer component 'pt1' in a pure procedure
|
!ERROR: Externally visible object 'dummy1a' may not be associated with pointer component 'pt1' in a pure procedure
|
||||||
x1a = t1(dummy1a)
|
x1a = t1(dummy1a)
|
||||||
x1a = t1(dummy2a)
|
x1a = t1(dummy2a)
|
||||||
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
|
|
||||||
x1a = t1(dummy3)
|
x1a = t1(dummy3)
|
||||||
!ERROR: Externally visible object 'dummy3a' may not be associated with pointer component 'pt1' in a pure procedure
|
|
||||||
x1a = t1(dummy3a)
|
x1a = t1(dummy3a)
|
||||||
! TODO when semantics handles coindexing:
|
! TODO when semantics handles coindexing:
|
||||||
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
|
! TODO !ERROR: Externally visible object may not be associated with a pointer in a pure procedure
|
||||||
|
@ -118,6 +115,21 @@ module module1
|
||||||
end subroutine subr
|
end subroutine subr
|
||||||
end subroutine
|
end subroutine
|
||||||
|
|
||||||
|
pure integer function pf1(dummy3)
|
||||||
|
real, pointer :: dummy3
|
||||||
|
type(t1) :: x1
|
||||||
|
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
|
||||||
|
x1 = t1(dummy3)
|
||||||
|
contains
|
||||||
|
pure subroutine subr(dummy3a)
|
||||||
|
real, pointer :: dummy3a
|
||||||
|
type(t1) :: x1a
|
||||||
|
!ERROR: Externally visible object 'dummy3' may not be associated with pointer component 'pt1' in a pure procedure
|
||||||
|
x1a = t1(dummy3)
|
||||||
|
x1a = t1(dummy3a)
|
||||||
|
end subroutine
|
||||||
|
end function
|
||||||
|
|
||||||
impure real function ipf1(dummy1, dummy2, dummy3, dummy4)
|
impure real function ipf1(dummy1, dummy2, dummy3, dummy4)
|
||||||
real, target :: local1
|
real, target :: local1
|
||||||
type(t1) :: x1
|
type(t1) :: x1
|
||||||
|
|
Loading…
Reference in New Issue