Skip to content

Commit d418a03

Browse files
authored
[flang] Fix error from semantics on use associated procedure pointer (#107928)
Use associated procedure pointers were eliciting bogus errors from semantics if their modules also contained generic procedure interfaces of the same name. (The compiler handles this case correctly when the specific procedure of the same name is not a pointer.) With this fix, the test case in #107784 no longer experiences semantic errors; however, it now crashes unexpectedly in lowering.
1 parent 37f94cd commit d418a03

File tree

6 files changed

+92
-13
lines changed

6 files changed

+92
-13
lines changed

flang/include/flang/Semantics/scope.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ class Scope {
138138
const_iterator cend() const { return symbols_.cend(); }
139139

140140
// Return symbols in declaration order (the iterators above are in name order)
141+
// When a generic procedure interface shadows a derived type or specific
142+
// procedure, only the generic's symbol appears in the output.
141143
SymbolVector GetSymbols() const;
142144
MutableSymbolVector GetSymbols();
143145

flang/lib/Semantics/compute-offsets.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ void ComputeOffsetsHelper::Compute(Scope &scope) {
114114
dependents_.find(symbol) == dependents_.end() &&
115115
equivalenceBlock_.find(symbol) == equivalenceBlock_.end()) {
116116
DoSymbol(*symbol);
117+
if (auto *generic{symbol->detailsIf<GenericDetails>()}) {
118+
if (Symbol * specific{generic->specific()};
119+
specific && !FindCommonBlockContaining(*specific)) {
120+
// might be a shadowed procedure pointer
121+
DoSymbol(*specific);
122+
}
123+
}
117124
}
118125
}
119126
// Ensure that the size is a multiple of the alignment

flang/lib/Semantics/expression.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ class ArgumentAnalyzer {
210210
// or procedure pointer reference in a ProcedureDesignator.
211211
MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
212212
const Symbol &last{ref.GetLastSymbol()};
213-
const Symbol &symbol{BypassGeneric(last).GetUltimate()};
213+
const Symbol &specific{BypassGeneric(last)};
214+
const Symbol &symbol{specific.GetUltimate()};
214215
if (semantics::IsProcedure(symbol)) {
215216
if (symbol.attrs().test(semantics::Attr::ABSTRACT)) {
216217
Say("Abstract procedure interface '%s' may not be used as a designator"_err_en_US,
@@ -226,6 +227,10 @@ MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
226227
} else if (!symbol.attrs().test(semantics::Attr::INTRINSIC)) {
227228
if (symbol.has<semantics::GenericDetails>()) {
228229
Say("'%s' is not a specific procedure"_err_en_US, last.name());
230+
} else if (IsProcedurePointer(specific)) {
231+
// For procedure pointers, retain associations so that data accesses
232+
// from client modules will work.
233+
return Expr<SomeType>{ProcedureDesignator{specific}};
229234
} else {
230235
return Expr<SomeType>{ProcedureDesignator{symbol}};
231236
}

flang/lib/Semantics/resolve-names.cpp

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

50805112
Symbol &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)) {

flang/lib/Semantics/symbol.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ const Symbol *GenericDetails::CheckSpecific() const {
210210
}
211211
Symbol *GenericDetails::CheckSpecific() {
212212
if (specific_ && !specific_->has<UseErrorDetails>()) {
213+
const Symbol &ultimate{specific_->GetUltimate()};
213214
for (const Symbol &proc : specificProcs_) {
214-
if (&proc == specific_) {
215+
if (&proc.GetUltimate() == &ultimate) {
215216
return nullptr;
216217
}
217218
}

flang/test/Semantics/generic10.f90

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
2+
module m
3+
procedure(func), pointer :: foo
4+
interface foo
5+
procedure :: foo
6+
end interface
7+
contains
8+
function func(x)
9+
func = x
10+
end
11+
end
12+
13+
program main
14+
use m
15+
!CHECK: foo => func
16+
foo => func
17+
end

0 commit comments

Comments
 (0)