Skip to content

Commit 693c83e

Browse files
committed
[flang] Correct definability checking for INTENT(IN) pointers
An INTENT(IN) attribute on a pointer dummy argument prevents modification of the pointer itself only, not modification of any component of its target. Fix this case without breaking definability checking for pointer components of non-pointer INTENT(IN) dummy arguments.
1 parent 8f6f5ec commit 693c83e

File tree

2 files changed

+32
-6
lines changed

2 files changed

+32
-6
lines changed

flang/lib/Semantics/definable.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ static const Symbol &GetRelevantSymbol(const evaluate::DataRef &dataRef,
8989

9090
// Check the leftmost (or only) symbol from a data-ref or expression.
9191
static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
92-
const Scope &scope, DefinabilityFlags flags, const Symbol &original) {
92+
const Scope &scope, DefinabilityFlags flags, const Symbol &original,
93+
bool isWholeSymbol) {
9394
const Symbol &ultimate{original.GetUltimate()};
9495
bool isPointerDefinition{flags.test(DefinabilityFlag::PointerDefinition)};
9596
bool acceptAllocatable{flags.test(DefinabilityFlag::AcceptAllocatable)};
@@ -104,15 +105,17 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
104105
} else if (auto dataRef{evaluate::ExtractDataRef(
105106
*association->expr(), true, true)}) {
106107
return WhyNotDefinableBase(at, scope, flags,
107-
GetRelevantSymbol(*dataRef, isPointerDefinition, acceptAllocatable));
108+
GetRelevantSymbol(*dataRef, isPointerDefinition, acceptAllocatable),
109+
isWholeSymbol);
108110
}
109111
}
110112
if (isTargetDefinition) {
111113
} else if (!isPointerDefinition && !IsVariableName(ultimate)) {
112114
return BlameSymbol(at, "'%s' is not a variable"_en_US, original);
113115
} else if (IsProtected(ultimate) && IsUseAssociated(original, scope)) {
114116
return BlameSymbol(at, "'%s' is protected in this scope"_en_US, original);
115-
} else if (IsIntentIn(ultimate)) {
117+
} else if (IsIntentIn(ultimate) &&
118+
(!IsPointer(ultimate) || (isWholeSymbol && isPointerDefinition))) {
116119
return BlameSymbol(
117120
at, "'%s' is an INTENT(IN) dummy argument"_en_US, original);
118121
}
@@ -165,6 +168,12 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
165168
static std::optional<parser::Message> WhyNotDefinableLast(parser::CharBlock at,
166169
const Scope &scope, DefinabilityFlags flags, const Symbol &original) {
167170
const Symbol &ultimate{original.GetUltimate()};
171+
if (const auto *association{ultimate.detailsIf<AssocEntityDetails>()}) {
172+
if (auto dataRef{
173+
evaluate::ExtractDataRef(*association->expr(), true, true)}) {
174+
return WhyNotDefinableLast(at, scope, flags, dataRef->GetLastSymbol());
175+
}
176+
}
168177
if (flags.test(DefinabilityFlag::PointerDefinition)) {
169178
if (flags.test(DefinabilityFlag::AcceptAllocatable)) {
170179
if (!IsAllocatableOrObjectPointer(&ultimate)) {
@@ -216,7 +225,8 @@ static std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
216225
const Symbol &base{GetRelevantSymbol(dataRef,
217226
flags.test(DefinabilityFlag::PointerDefinition),
218227
flags.test(DefinabilityFlag::AcceptAllocatable))};
219-
if (auto whyNot{WhyNotDefinableBase(at, scope, flags, base)}) {
228+
if (auto whyNot{WhyNotDefinableBase(at, scope, flags, base,
229+
std::holds_alternative<evaluate::SymbolRef>(dataRef.u))}) {
220230
return whyNot;
221231
} else {
222232
return WhyNotDefinableLast(at, scope, flags, dataRef.GetLastSymbol());
@@ -231,12 +241,13 @@ static std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
231241
const Symbol &base{GetRelevantSymbol(dataRef, false, false)};
232242
DefinabilityFlags baseFlags{flags};
233243
baseFlags.reset(DefinabilityFlag::PointerDefinition);
234-
return WhyNotDefinableBase(at, scope, baseFlags, base);
244+
return WhyNotDefinableBase(at, scope, baseFlags, base,
245+
std::holds_alternative<evaluate::SymbolRef>(dataRef.u));
235246
}
236247

237248
std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
238249
const Scope &scope, DefinabilityFlags flags, const Symbol &original) {
239-
if (auto base{WhyNotDefinableBase(at, scope, flags, original)}) {
250+
if (auto base{WhyNotDefinableBase(at, scope, flags, original, true)}) {
240251
return base;
241252
}
242253
return WhyNotDefinableLast(at, scope, flags, original);

flang/test/Semantics/definable01.f90

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,19 @@ subroutine test3a(op)
8282
subroutine test3b(pp)
8383
procedure(sin), pointer, intent(in out) :: pp
8484
end subroutine
85+
subroutine test4(p)
86+
type(ptype), pointer, intent(in) :: p
87+
p%x = 1.
88+
p%ptr = 1. ! ok
89+
nullify(p%ptr) ! ok
90+
!CHECK: error: 'p' may not appear in NULLIFY
91+
!CHECK: because: 'p' is an INTENT(IN) dummy argument
92+
nullify(p)
93+
end
94+
subroutine test5(np)
95+
type(ptype), intent(in) :: np
96+
!CHECK: error: 'ptr' may not appear in NULLIFY
97+
!CHECK: because: 'np' is an INTENT(IN) dummy argument
98+
nullify(np%ptr)
99+
end
85100
end module

0 commit comments

Comments
 (0)