Skip to content

Commit 962863d

Browse files
committed
[flang] Catch attempts to copy pointers in allocatables in PURE
In a pure context, a pointer acquired from an INTENT(IN) dummy argument may not be copied. Catch the case in which the pointer is a component of an allocatable component at some depth of nesting. (This patch adds a new component iterator kind that is a variant of a potential subobject component iterator; it visits all potential subobject components, plus pointers, into which it does not descend.) Differential Revision: https://reviews.llvm.org/D139161
1 parent e311601 commit 962863d

File tree

4 files changed

+31
-35
lines changed

4 files changed

+31
-35
lines changed

flang/include/flang/Semantics/tools.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &);
383383
// its non-POINTER components and the potential subobject components of
384384
// its non-POINTER derived type components. (The lifetime of each
385385
// potential subobject component is that of the entire instance.)
386+
// - PotentialAndPointer subobject components of a derived type are the
387+
// closure of
388+
// its components (including POINTERs) and the PotentialAndPointer subobject
389+
// components of its non-POINTER derived type components.
386390
// Parent and procedure components are considered against these definitions.
387391
// For this kind of iterator, the component tree is recursively visited in the
388392
// following order:
@@ -413,7 +417,8 @@ std::list<std::list<SymbolRef>> GetStorageAssociations(const Scope &);
413417
// ....
414418
// }
415419

416-
ENUM_CLASS(ComponentKind, Ordered, Direct, Ultimate, Potential, Scope)
420+
ENUM_CLASS(ComponentKind, Ordered, Direct, Ultimate, Potential, Scope,
421+
PotentialAndPointer)
417422

418423
template <ComponentKind componentKind> class ComponentIterator {
419424
public:
@@ -535,11 +540,14 @@ extern template class ComponentIterator<ComponentKind::Direct>;
535540
extern template class ComponentIterator<ComponentKind::Ultimate>;
536541
extern template class ComponentIterator<ComponentKind::Potential>;
537542
extern template class ComponentIterator<ComponentKind::Scope>;
543+
extern template class ComponentIterator<ComponentKind::PotentialAndPointer>;
538544
using OrderedComponentIterator = ComponentIterator<ComponentKind::Ordered>;
539545
using DirectComponentIterator = ComponentIterator<ComponentKind::Direct>;
540546
using UltimateComponentIterator = ComponentIterator<ComponentKind::Ultimate>;
541547
using PotentialComponentIterator = ComponentIterator<ComponentKind::Potential>;
542548
using ScopeComponentIterator = ComponentIterator<ComponentKind::Scope>;
549+
using PotentialAndPointerComponentIterator =
550+
ComponentIterator<ComponentKind::PotentialAndPointer>;
543551

544552
// Common component searches, the iterator returned is referring to the first
545553
// component, according to the order defined for the related ComponentIterator,

flang/lib/Semantics/assignment.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ static std::optional<std::string> GetPointerComponentDesignatorName(
9898
const SomeExpr &expr) {
9999
if (const auto *derived{
100100
evaluate::GetDerivedTypeSpec(evaluate::DynamicType::From(expr))}) {
101-
UltimateComponentIterator ultimates{*derived};
101+
PotentialAndPointerComponentIterator potentials{*derived};
102102
if (auto pointer{
103-
std::find_if(ultimates.begin(), ultimates.end(), IsPointer)}) {
103+
std::find_if(potentials.begin(), potentials.end(), IsPointer)}) {
104104
return pointer.BuildResultDesignatorName();
105105
}
106106
}
@@ -116,7 +116,7 @@ bool CheckCopyabilityInPureScope(parser::ContextualMessages &messages,
116116
if (auto pointer{GetPointerComponentDesignatorName(expr)}) {
117117
evaluate::SayWithDeclaration(messages, *base,
118118
"A pure subprogram may not copy the value of '%s' because it is %s"
119-
" and has the POINTER component '%s'"_err_en_US,
119+
" and has the POINTER potential subobject component '%s'"_err_en_US,
120120
base->name(), why, *pointer);
121121
return false;
122122
}

flang/lib/Semantics/tools.cpp

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -806,34 +806,6 @@ bool IsModuleProcedure(const Symbol &symbol) {
806806
return ClassifyProcedure(symbol) == ProcedureDefinitionClass::Module;
807807
}
808808

809-
PotentialComponentIterator::const_iterator FindPolymorphicPotentialComponent(
810-
const DerivedTypeSpec &derived) {
811-
PotentialComponentIterator potentials{derived};
812-
return std::find_if(
813-
potentials.begin(), potentials.end(), [](const Symbol &component) {
814-
if (const auto *details{component.detailsIf<ObjectEntityDetails>()}) {
815-
const DeclTypeSpec *type{details->type()};
816-
return type && type->IsPolymorphic();
817-
}
818-
return false;
819-
});
820-
}
821-
822-
bool IsOrContainsPolymorphicComponent(const Symbol &original) {
823-
const Symbol &symbol{ResolveAssociations(original)};
824-
if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) {
825-
if (const DeclTypeSpec * type{details->type()}) {
826-
if (type->IsPolymorphic()) {
827-
return true;
828-
}
829-
if (const DerivedTypeSpec * derived{type->AsDerived()}) {
830-
return (bool)FindPolymorphicPotentialComponent(*derived);
831-
}
832-
}
833-
}
834-
return false;
835-
}
836-
837809
class ImageControlStmtHelper {
838810
using ImageControlStmts =
839811
std::variant<parser::ChangeTeamConstruct, parser::CriticalConstruct,
@@ -1130,6 +1102,9 @@ ComponentIterator<componentKind>::const_iterator::PlanComponentTraversal(
11301102
traverse = !IsPointer(component);
11311103
} else if constexpr (componentKind == ComponentKind::Scope) {
11321104
traverse = !IsAllocatableOrPointer(component);
1105+
} else if constexpr (componentKind ==
1106+
ComponentKind::PotentialAndPointer) {
1107+
traverse = !IsPointer(component);
11331108
}
11341109
if (traverse) {
11351110
const Symbol &newTypeSymbol{derived->typeSymbol()};
@@ -1165,6 +1140,8 @@ static bool StopAtComponentPre(const Symbol &component) {
11651140
component.get<ObjectEntityDetails>().type()->AsIntrinsic());
11661141
} else if constexpr (componentKind == ComponentKind::Potential) {
11671142
return !IsPointer(component);
1143+
} else if constexpr (componentKind == ComponentKind::PotentialAndPointer) {
1144+
return true;
11681145
}
11691146
}
11701147

@@ -1233,6 +1210,7 @@ template class ComponentIterator<ComponentKind::Direct>;
12331210
template class ComponentIterator<ComponentKind::Ultimate>;
12341211
template class ComponentIterator<ComponentKind::Potential>;
12351212
template class ComponentIterator<ComponentKind::Scope>;
1213+
template class ComponentIterator<ComponentKind::PotentialAndPointer>;
12361214

12371215
UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
12381216
const DerivedTypeSpec &derived) {

flang/test/Semantics/call12.f90

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ module m
1717
type :: hasCoarray
1818
real, allocatable :: co[:]
1919
end type
20+
type :: hasHiddenPtr
21+
type(hasPtr), allocatable :: a
22+
end type
2023
contains
2124
integer pure function purefunc(x)
2225
integer, intent(in) :: x
@@ -26,14 +29,17 @@ integer pure function f00(p0)
2629
procedure(purefunc) :: p0
2730
f00 = p0(1)
2831
end function
29-
pure function test(ptr, in, hpd)
32+
pure function test(ptr, in, hpd, hhpd)
3033
use used
3134
type(t), pointer :: ptr, ptr2
3235
type(t), target, intent(in) :: in
3336
type(t), target :: y, z
3437
type(hasPtr) :: hp
3538
type(hasPtr), intent(in) :: hpd
39+
type(hasHiddenPtr) :: hhp
40+
type(hasHiddenPtr), intent(in) :: hhpd
3641
type(hasPtr), allocatable :: alloc
42+
type(hasHiddenPtr), allocatable :: hpAlloc
3743
type(hasCoarray), pointer :: hcp
3844
integer :: n
3945
common /block/ y
@@ -76,10 +82,14 @@ pure function test(ptr, in, hpd)
7682
n = size([hasPtr(ptr%a)]) ! C1594(4)
7783
!ERROR: Externally visible object 'in' may not be associated with pointer component 'p' in a pure procedure
7884
n = size([hasPtr(in%a)]) ! C1594(4)
79-
!ERROR: A pure subprogram may not copy the value of 'hpd' because it is an INTENT(IN) dummy argument and has the POINTER component '%p'
85+
!ERROR: A pure subprogram may not copy the value of 'hpd' because it is an INTENT(IN) dummy argument and has the POINTER potential subobject component '%p'
8086
hp = hpd ! C1594(5)
81-
!ERROR: A pure subprogram may not copy the value of 'hpd' because it is an INTENT(IN) dummy argument and has the POINTER component '%p'
87+
!ERROR: A pure subprogram may not copy the value of 'hpd' because it is an INTENT(IN) dummy argument and has the POINTER potential subobject component '%p'
8288
allocate(alloc, source=hpd)
89+
!ERROR: A pure subprogram may not copy the value of 'hhpd' because it is an INTENT(IN) dummy argument and has the POINTER potential subobject component '%a%p'
90+
hhp = hhpd
91+
!ERROR: A pure subprogram may not copy the value of 'hhpd' because it is an INTENT(IN) dummy argument and has the POINTER potential subobject component '%a%p'
92+
allocate(hpAlloc, source=hhpd)
8393
!ERROR: Actual procedure argument for dummy argument 'p0=' of a PURE procedure must have an explicit interface
8494
n = f00(extfunc)
8595
contains

0 commit comments

Comments
 (0)