@@ -60,37 +60,44 @@ static std::optional<parser::Message> CheckDefinabilityInPureScope(
60
60
return std::nullopt;
61
61
}
62
62
63
- // When a DataRef contains pointers, gets the rightmost one (unless it is
64
- // the entity being defined, in which case the last pointer above it);
65
- // otherwise, returns the leftmost symbol. The resulting symbol is the
66
- // relevant base object for definabiliy checking. Examples:
67
- // ptr1%ptr2 => ... -> ptr1
68
- // nonptr%ptr => ... -> nonptr
69
- // nonptr%ptr = ... -> ptr
70
- // ptr1%ptr2 = ... -> ptr2
71
- // ptr1%ptr2%nonptr = ... -> ptr2
72
- // nonptr1%nonptr2 = ... -> nonptr1
73
- static const Symbol &GetRelevantSymbol (const evaluate::DataRef &dataRef,
74
- bool isPointerDefinition, bool acceptAllocatable) {
75
- if (isPointerDefinition) {
76
- if (const auto *component{std::get_if<evaluate::Component>(&dataRef.u )}) {
77
- if (IsPointer (component->GetLastSymbol ()) ||
78
- (acceptAllocatable && IsAllocatable (component->GetLastSymbol ()))) {
79
- return GetRelevantSymbol (component->base (), false , false );
63
+ // True when the object being defined is not a subobject of the base
64
+ // object, e.g. X%PTR = 1., X%PTR%PTR2 => T (but not X%PTR => T).
65
+ // F'2023 9.4.2p5
66
+ static bool DefinesComponentPointerTarget (
67
+ const evaluate::DataRef &dataRef, DefinabilityFlags flags) {
68
+ if (const evaluate::Component *
69
+ component{common::visit (
70
+ common::visitors{
71
+ [](const SymbolRef &) -> const evaluate::Component * {
72
+ return nullptr ;
73
+ },
74
+ [](const evaluate::Component &component) { return &component; },
75
+ [](const evaluate::ArrayRef &aRef) {
76
+ return aRef.base ().UnwrapComponent ();
77
+ },
78
+ [](const evaluate::CoarrayRef &aRef)
79
+ -> const evaluate::Component * { return nullptr ; },
80
+ },
81
+ dataRef.u )}) {
82
+ const Symbol &compSym{component->GetLastSymbol ()};
83
+ if (IsPointer (compSym) ||
84
+ (flags.test (DefinabilityFlag::AcceptAllocatable) &&
85
+ IsAllocatable (compSym))) {
86
+ if (!flags.test (DefinabilityFlag::PointerDefinition)) {
87
+ return true ;
80
88
}
81
89
}
82
- }
83
- if (const Symbol * lastPointer{GetLastPointerSymbol (dataRef)}) {
84
- return *lastPointer;
90
+ flags.reset (DefinabilityFlag::PointerDefinition);
91
+ return DefinesComponentPointerTarget (component->base (), flags);
85
92
} else {
86
- return dataRef. GetFirstSymbol () ;
93
+ return false ;
87
94
}
88
95
}
89
96
90
97
// Check the leftmost (or only) symbol from a data-ref or expression.
91
98
static std::optional<parser::Message> WhyNotDefinableBase (parser::CharBlock at,
92
99
const Scope &scope, DefinabilityFlags flags, const Symbol &original,
93
- bool isWholeSymbol) {
100
+ bool isWholeSymbol, bool isComponentPointerTarget ) {
94
101
const Symbol &ultimate{original.GetUltimate ()};
95
102
bool isPointerDefinition{flags.test (DefinabilityFlag::PointerDefinition)};
96
103
bool acceptAllocatable{flags.test (DefinabilityFlag::AcceptAllocatable)};
@@ -104,12 +111,14 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
104
111
" Construct association '%s' has a vector subscript" _en_US, original);
105
112
} else if (auto dataRef{evaluate::ExtractDataRef (
106
113
*association->expr (), true , true )}) {
107
- return WhyNotDefinableBase (at, scope, flags,
108
- GetRelevantSymbol (*dataRef, isPointerDefinition, acceptAllocatable),
109
- isWholeSymbol);
114
+ return WhyNotDefinableBase (at, scope, flags, dataRef->GetFirstSymbol (),
115
+ isWholeSymbol &&
116
+ std::holds_alternative<evaluate::SymbolRef>(dataRef->u ),
117
+ isComponentPointerTarget ||
118
+ DefinesComponentPointerTarget (*dataRef, flags));
110
119
}
111
120
}
112
- if (isTargetDefinition) {
121
+ if (isTargetDefinition || isComponentPointerTarget ) {
113
122
} else if (!isPointerDefinition && !IsVariableName (ultimate)) {
114
123
return BlameSymbol (at, " '%s' is not a variable" _en_US, original);
115
124
} else if (IsProtected (ultimate) && IsUseAssociated (original, scope)) {
@@ -121,7 +130,7 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
121
130
}
122
131
if (const Scope * pure{FindPureProcedureContaining (scope)}) {
123
132
// Additional checking for pure subprograms.
124
- if (!isTargetDefinition) {
133
+ if (!isTargetDefinition || isComponentPointerTarget ) {
125
134
if (auto msg{CheckDefinabilityInPureScope (
126
135
at, original, ultimate, scope, *pure)}) {
127
136
return msg;
@@ -222,35 +231,24 @@ static std::optional<parser::Message> WhyNotDefinableLast(parser::CharBlock at,
222
231
static std::optional<parser::Message> WhyNotDefinable (parser::CharBlock at,
223
232
const Scope &scope, DefinabilityFlags flags,
224
233
const evaluate::DataRef &dataRef) {
225
- const Symbol &base{GetRelevantSymbol (dataRef,
226
- flags.test (DefinabilityFlag::PointerDefinition),
227
- flags.test (DefinabilityFlag::AcceptAllocatable))};
228
- if (auto whyNot{WhyNotDefinableBase (at, scope, flags, base,
229
- std::holds_alternative<evaluate::SymbolRef>(dataRef.u ))}) {
234
+ if (auto whyNot{
235
+ WhyNotDefinableBase (at, scope, flags, dataRef.GetFirstSymbol (),
236
+ std::holds_alternative<evaluate::SymbolRef>(dataRef.u ),
237
+ DefinesComponentPointerTarget (dataRef, flags))}) {
230
238
return whyNot;
231
239
} else {
232
240
return WhyNotDefinableLast (at, scope, flags, dataRef.GetLastSymbol ());
233
241
}
234
242
}
235
243
236
- // Checks a NOPASS procedure pointer component
237
- static std::optional<parser::Message> WhyNotDefinable (parser::CharBlock at,
238
- const Scope &scope, DefinabilityFlags flags,
239
- const evaluate::Component &component) {
240
- const evaluate::DataRef &dataRef{component.base ()};
241
- const Symbol &base{GetRelevantSymbol (dataRef, false , false )};
242
- DefinabilityFlags baseFlags{flags};
243
- baseFlags.reset (DefinabilityFlag::PointerDefinition);
244
- return WhyNotDefinableBase (at, scope, baseFlags, base,
245
- std::holds_alternative<evaluate::SymbolRef>(dataRef.u ));
246
- }
247
-
248
244
std::optional<parser::Message> WhyNotDefinable (parser::CharBlock at,
249
245
const Scope &scope, DefinabilityFlags flags, const Symbol &original) {
250
- if (auto base{WhyNotDefinableBase (at, scope, flags, original, true )}) {
246
+ if (auto base{WhyNotDefinableBase (at, scope, flags, original,
247
+ /* isWholeSymbol=*/ true , /* isComponentPointerTarget=*/ false )}) {
251
248
return base;
249
+ } else {
250
+ return WhyNotDefinableLast (at, scope, flags, original);
252
251
}
253
- return WhyNotDefinableLast (at, scope, flags, original);
254
252
}
255
253
256
254
class DuplicatedSubscriptFinder
@@ -370,7 +368,10 @@ std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
370
368
*procSym, expr.AsFortran ());
371
369
}
372
370
if (const auto *component{procDesignator->GetComponent ()}) {
373
- return WhyNotDefinable (at, scope, flags, *component);
371
+ flags.reset (DefinabilityFlag::PointerDefinition);
372
+ return WhyNotDefinableBase (at, scope, flags,
373
+ component->base ().GetFirstSymbol (), false ,
374
+ DefinesComponentPointerTarget (component->base (), flags));
374
375
} else {
375
376
return WhyNotDefinable (at, scope, flags, *procSym);
376
377
}
0 commit comments