@@ -618,6 +618,20 @@ class ScopeHandler : public ImplicitRulesVisitor {
618
618
return *derivedType;
619
619
}
620
620
}
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
+ }
621
635
}
622
636
if (symbol->CanReplaceDetails (details)) {
623
637
// update the existing symbol
@@ -3035,14 +3049,26 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
3035
3049
return ;
3036
3050
}
3037
3051
const Symbol &useUltimate{useSymbol.GetUltimate ()};
3052
+ const auto *useGeneric{useUltimate.detailsIf <GenericDetails>()};
3038
3053
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
+ }
3046
3072
}
3047
3073
3048
3074
Symbol &localUltimate{localSymbol->GetUltimate ()};
@@ -3066,10 +3092,7 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
3066
3092
// - anything other than a derived type, non-generic procedure, or
3067
3093
// generic procedure being combined with something other than an
3068
3094
// prior USE association of itself
3069
-
3070
3095
auto *localGeneric{localUltimate.detailsIf <GenericDetails>()};
3071
- const auto *useGeneric{useUltimate.detailsIf <GenericDetails>()};
3072
-
3073
3096
Symbol *localDerivedType{nullptr };
3074
3097
if (localUltimate.has <DerivedTypeDetails>()) {
3075
3098
localDerivedType = &localUltimate;
@@ -3261,6 +3284,15 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
3261
3284
// At this point, there must be at least one generic interface.
3262
3285
CHECK (localGeneric || (useGeneric && (localDerivedType || localProcedure)));
3263
3286
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
+
3264
3296
if (localGeneric) {
3265
3297
// Create a local copy of a previously use-associated generic so that
3266
3298
// it can be locally extended without corrupting the original.
@@ -5079,7 +5111,22 @@ bool DeclarationVisitor::HasCycle(
5079
5111
5080
5112
Symbol &DeclarationVisitor::DeclareProcEntity (
5081
5113
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)};
5083
5130
if (auto *details{symbol.detailsIf <ProcEntityDetails>()}) {
5084
5131
if (context ().HasError (symbol)) {
5085
5132
} else if (HasCycle (symbol, interface)) {
0 commit comments