@@ -618,6 +618,20 @@ class ScopeHandler : public ImplicitRulesVisitor {
618618 return *derivedType;
619619 }
620620 }
621+ } else if constexpr (std::is_same_v<ProcEntityDetails, D>) {
622+ if (auto *d{symbol->detailsIf <GenericDetails>()}) {
623+ if (!d->derivedType ()) {
624+ // procedure pointer with same name as a generic
625+ auto *specific{d->specific ()};
626+ if (!specific) {
627+ specific = &currScope ().MakeSymbol (name, attrs, std::move (details));
628+ d->set_specific (*specific);
629+ } else {
630+ SayAlreadyDeclared (name, *specific);
631+ }
632+ return *specific;
633+ }
634+ }
621635 }
622636 if (symbol->CanReplaceDetails (details)) {
623637 // update the existing symbol
@@ -3035,14 +3049,26 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
30353049 return ;
30363050 }
30373051 const Symbol &useUltimate{useSymbol.GetUltimate ()};
3052+ const auto *useGeneric{useUltimate.detailsIf <GenericDetails>()};
30383053 if (localSymbol->has <UnknownDetails>()) {
3039- localSymbol->set_details (UseDetails{localName, useSymbol});
3040- localSymbol->attrs () =
3041- useSymbol.attrs () & ~Attrs{Attr::PUBLIC, Attr::PRIVATE, Attr::SAVE};
3042- localSymbol->implicitAttrs () =
3043- localSymbol->attrs () & Attrs{Attr::ASYNCHRONOUS, Attr::VOLATILE};
3044- localSymbol->flags () = useSymbol.flags ();
3045- return ;
3054+ if (useGeneric && useGeneric->specific () &&
3055+ IsProcedurePointer (*useGeneric->specific ())) {
3056+ // We are use-associating a generic that shadows a procedure pointer.
3057+ // Local references that might be made to that procedure pointer should
3058+ // use a UseDetails symbol for proper data addressing. So create an
3059+ // empty local generic now into which the use-associated generic may
3060+ // be copied.
3061+ localSymbol->set_details (GenericDetails{});
3062+ localSymbol->get <GenericDetails>().set_kind (useGeneric->kind ());
3063+ } else { // just create UseDetails
3064+ localSymbol->set_details (UseDetails{localName, useSymbol});
3065+ localSymbol->attrs () =
3066+ useSymbol.attrs () & ~Attrs{Attr::PUBLIC, Attr::PRIVATE, Attr::SAVE};
3067+ localSymbol->implicitAttrs () =
3068+ localSymbol->attrs () & Attrs{Attr::ASYNCHRONOUS, Attr::VOLATILE};
3069+ localSymbol->flags () = useSymbol.flags ();
3070+ return ;
3071+ }
30463072 }
30473073
30483074 Symbol &localUltimate{localSymbol->GetUltimate ()};
@@ -3066,10 +3092,7 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
30663092 // - anything other than a derived type, non-generic procedure, or
30673093 // generic procedure being combined with something other than an
30683094 // prior USE association of itself
3069-
30703095 auto *localGeneric{localUltimate.detailsIf <GenericDetails>()};
3071- const auto *useGeneric{useUltimate.detailsIf <GenericDetails>()};
3072-
30733096 Symbol *localDerivedType{nullptr };
30743097 if (localUltimate.has <DerivedTypeDetails>()) {
30753098 localDerivedType = &localUltimate;
@@ -3261,6 +3284,15 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
32613284 // At this point, there must be at least one generic interface.
32623285 CHECK (localGeneric || (useGeneric && (localDerivedType || localProcedure)));
32633286
3287+ // Ensure that a use-associated specific procedure that is a procedure
3288+ // pointer is properly represented as a USE association of an entity.
3289+ if (IsProcedurePointer (useProcedure)) {
3290+ Symbol &combined{currScope ().MakeSymbol (localSymbol->name (),
3291+ useProcedure->attrs (), UseDetails{localName, *useProcedure})};
3292+ combined.flags () |= useProcedure->flags ();
3293+ combinedProcedure = &combined;
3294+ }
3295+
32643296 if (localGeneric) {
32653297 // Create a local copy of a previously use-associated generic so that
32663298 // it can be locally extended without corrupting the original.
@@ -5079,7 +5111,22 @@ bool DeclarationVisitor::HasCycle(
50795111
50805112Symbol &DeclarationVisitor::DeclareProcEntity (
50815113 const parser::Name &name, Attrs attrs, const Symbol *interface) {
5082- Symbol &symbol{DeclareEntity<ProcEntityDetails>(name, attrs)};
5114+ Symbol *proc{nullptr };
5115+ if (auto *extant{FindInScope (name)}) {
5116+ if (auto *d{extant->detailsIf <GenericDetails>()}; d && !d->derivedType ()) {
5117+ // procedure pointer with same name as a generic
5118+ if (auto *specific{d->specific ()}) {
5119+ SayAlreadyDeclared (name, *specific);
5120+ } else {
5121+ // Create the ProcEntityDetails symbol in the scope as the "specific()"
5122+ // symbol behind an existing GenericDetails symbol of the same name.
5123+ proc = &Resolve (name,
5124+ currScope ().MakeSymbol (name.source , attrs, ProcEntityDetails{}));
5125+ d->set_specific (*proc);
5126+ }
5127+ }
5128+ }
5129+ Symbol &symbol{proc ? *proc : DeclareEntity<ProcEntityDetails>(name, attrs)};
50835130 if (auto *details{symbol.detailsIf <ProcEntityDetails>()}) {
50845131 if (context ().HasError (symbol)) {
50855132 } else if (HasCycle (symbol, interface)) {
0 commit comments