@@ -60,37 +60,44 @@ static std::optional<parser::Message> CheckDefinabilityInPureScope(
6060 return std::nullopt ;
6161}
6262
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 ;
8088 }
8189 }
82- }
83- if (const Symbol * lastPointer{GetLastPointerSymbol (dataRef)}) {
84- return *lastPointer;
90+ flags.reset (DefinabilityFlag::PointerDefinition);
91+ return DefinesComponentPointerTarget (component->base (), flags);
8592 } else {
86- return dataRef. GetFirstSymbol () ;
93+ return false ;
8794 }
8895}
8996
9097// Check the leftmost (or only) symbol from a data-ref or expression.
9198static std::optional<parser::Message> WhyNotDefinableBase (parser::CharBlock at,
9299 const Scope &scope, DefinabilityFlags flags, const Symbol &original,
93- bool isWholeSymbol) {
100+ bool isWholeSymbol, bool isComponentPointerTarget ) {
94101 const Symbol &ultimate{original.GetUltimate ()};
95102 bool isPointerDefinition{flags.test (DefinabilityFlag::PointerDefinition)};
96103 bool acceptAllocatable{flags.test (DefinabilityFlag::AcceptAllocatable)};
@@ -104,12 +111,14 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
104111 " Construct association '%s' has a vector subscript" _en_US, original);
105112 } else if (auto dataRef{evaluate::ExtractDataRef (
106113 *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));
110119 }
111120 }
112- if (isTargetDefinition) {
121+ if (isTargetDefinition || isComponentPointerTarget ) {
113122 } else if (!isPointerDefinition && !IsVariableName (ultimate)) {
114123 return BlameSymbol (at, " '%s' is not a variable" _en_US, original);
115124 } else if (IsProtected (ultimate) && IsUseAssociated (original, scope)) {
@@ -121,7 +130,7 @@ static std::optional<parser::Message> WhyNotDefinableBase(parser::CharBlock at,
121130 }
122131 if (const Scope * pure{FindPureProcedureContaining (scope)}) {
123132 // Additional checking for pure subprograms.
124- if (!isTargetDefinition) {
133+ if (!isTargetDefinition || isComponentPointerTarget ) {
125134 if (auto msg{CheckDefinabilityInPureScope (
126135 at, original, ultimate, scope, *pure)}) {
127136 return msg;
@@ -222,35 +231,24 @@ static std::optional<parser::Message> WhyNotDefinableLast(parser::CharBlock at,
222231static std::optional<parser::Message> WhyNotDefinable (parser::CharBlock at,
223232 const Scope &scope, DefinabilityFlags flags,
224233 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))}) {
230238 return whyNot;
231239 } else {
232240 return WhyNotDefinableLast (at, scope, flags, dataRef.GetLastSymbol ());
233241 }
234242}
235243
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-
248244std::optional<parser::Message> WhyNotDefinable (parser::CharBlock at,
249245 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 )}) {
251248 return base;
249+ } else {
250+ return WhyNotDefinableLast (at, scope, flags, original);
252251 }
253- return WhyNotDefinableLast (at, scope, flags, original);
254252}
255253
256254class DuplicatedSubscriptFinder
@@ -370,7 +368,10 @@ std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
370368 *procSym, expr.AsFortran ());
371369 }
372370 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));
374375 } else {
375376 return WhyNotDefinable (at, scope, flags, *procSym);
376377 }
0 commit comments