@@ -60,37 +60,31 @@ 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 auto *component{std::get_if<evaluate::Component>(&dataRef.u )}) {
69
+ const Symbol &compSym{component->GetLastSymbol ()};
70
+ if (IsPointer (compSym) ||
71
+ (flags.test (DefinabilityFlag::AcceptAllocatable) &&
72
+ IsAllocatable (compSym))) {
73
+ if (!flags.test (DefinabilityFlag::PointerDefinition)) {
74
+ return true ;
80
75
}
81
76
}
82
- }
83
- if (const Symbol * lastPointer{GetLastPointerSymbol (dataRef)}) {
84
- return *lastPointer;
77
+ flags.reset (DefinabilityFlag::PointerDefinition);
78
+ return DefinesComponentPointerTarget (component->base (), flags);
85
79
} else {
86
- return dataRef. GetFirstSymbol () ;
80
+ return false ;
87
81
}
88
82
}
89
83
90
84
// Check the leftmost (or only) symbol from a data-ref or expression.
91
85
static std::optional<parser::Message> WhyNotDefinableBase (parser::CharBlock at,
92
86
const Scope &scope, DefinabilityFlags flags, const Symbol &original,
93
- bool isWholeSymbol) {
87
+ bool isWholeSymbol, bool isComponentPointerTarget ) {
94
88
const Symbol &ultimate{original.GetUltimate ()};
95
89
bool isPointerDefinition{flags.test (DefinabilityFlag::PointerDefinition)};
96
90
bool acceptAllocatable{flags.test (DefinabilityFlag::AcceptAllocatable)};
@@ -104,12 +98,14 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
104
98
" Construct association '%s' has a vector subscript" _en_US, original);
105
99
} else if (auto dataRef{evaluate::ExtractDataRef (
106
100
*association->expr (), true , true )}) {
107
- return WhyNotDefinableBase (at, scope, flags,
108
- GetRelevantSymbol (*dataRef, isPointerDefinition, acceptAllocatable),
109
- isWholeSymbol);
101
+ return WhyNotDefinableBase (at, scope, flags, dataRef->GetFirstSymbol (),
102
+ isWholeSymbol &&
103
+ std::holds_alternative<evaluate::SymbolRef>(dataRef->u ),
104
+ isComponentPointerTarget ||
105
+ DefinesComponentPointerTarget (*dataRef, flags));
110
106
}
111
107
}
112
- if (isTargetDefinition) {
108
+ if (isTargetDefinition || isComponentPointerTarget ) {
113
109
} else if (!isPointerDefinition && !IsVariableName (ultimate)) {
114
110
return BlameSymbol (at, " '%s' is not a variable" _en_US, original);
115
111
} else if (IsProtected (ultimate) && IsUseAssociated (original, scope)) {
@@ -121,7 +117,7 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
121
117
}
122
118
if (const Scope * pure{FindPureProcedureContaining (scope)}) {
123
119
// Additional checking for pure subprograms.
124
- if (!isTargetDefinition) {
120
+ if (!isTargetDefinition || isComponentPointerTarget ) {
125
121
if (auto msg{CheckDefinabilityInPureScope (
126
122
at, original, ultimate, scope, *pure)}) {
127
123
return msg;
@@ -222,35 +218,24 @@ static std::optional<parser::Message> WhyNotDefinableLast(parser::CharBlock at,
222
218
static std::optional<parser::Message> WhyNotDefinable (parser::CharBlock at,
223
219
const Scope &scope, DefinabilityFlags flags,
224
220
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 ))}) {
221
+ if (auto whyNot{
222
+ WhyNotDefinableBase (at, scope, flags, dataRef.GetFirstSymbol (),
223
+ std::holds_alternative<evaluate::SymbolRef>(dataRef.u ),
224
+ DefinesComponentPointerTarget (dataRef, flags))}) {
230
225
return whyNot;
231
226
} else {
232
227
return WhyNotDefinableLast (at, scope, flags, dataRef.GetLastSymbol ());
233
228
}
234
229
}
235
230
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
231
std::optional<parser::Message> WhyNotDefinable (parser::CharBlock at,
249
232
const Scope &scope, DefinabilityFlags flags, const Symbol &original) {
250
- if (auto base{WhyNotDefinableBase (at, scope, flags, original, true )}) {
233
+ if (auto base{WhyNotDefinableBase (at, scope, flags, original,
234
+ /* isWholeSymbol=*/ true , /* isComponentPointerTarget=*/ false )}) {
251
235
return base;
236
+ } else {
237
+ return WhyNotDefinableLast (at, scope, flags, original);
252
238
}
253
- return WhyNotDefinableLast (at, scope, flags, original);
254
239
}
255
240
256
241
class DuplicatedSubscriptFinder
@@ -370,7 +355,10 @@ std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
370
355
*procSym, expr.AsFortran ());
371
356
}
372
357
if (const auto *component{procDesignator->GetComponent ()}) {
373
- return WhyNotDefinable (at, scope, flags, *component);
358
+ flags.reset (DefinabilityFlag::PointerDefinition);
359
+ return WhyNotDefinableBase (at, scope, flags,
360
+ component->base ().GetFirstSymbol (), false ,
361
+ DefinesComponentPointerTarget (component->base (), flags));
374
362
} else {
375
363
return WhyNotDefinable (at, scope, flags, *procSym);
376
364
}
0 commit comments