Skip to content

Commit e162dc6

Browse files
committed
[flang] Fix symbol table bugs with ENTRY statements
Dummy arguments of ENTRY statements in execution parts were not being created as objects, nor were they being implicitly typed. When the symbol corresponding to an alternate ENTRY point already exists (by that name) due to having been referenced in an earlier call, name resolution used to delete the extant symbol. This isn't the right thing to do -- the extant symbol will be pointed to by parser::Name nodes in the parse tree while no longer being part of any Scope. Differential Review: https://reviews.llvm.org/D102948
1 parent 40df1b1 commit e162dc6

File tree

2 files changed

+42
-38
lines changed

2 files changed

+42
-38
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,9 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
746746
std::optional<SourceName> source;
747747
} funcInfo_;
748748

749+
// Edits an existing symbol created for earlier calls to a subprogram or ENTRY
750+
// so that it can be replaced by a later definition.
751+
bool HandlePreviousCalls(const parser::Name &, Symbol &, Symbol::Flag);
749752
// Create a subprogram symbol in the current scope and push a new scope.
750753
void CheckExtantProc(const parser::Name &, Symbol::Flag);
751754
Symbol &PushSubprogramScope(const parser::Name &, Symbol::Flag);
@@ -3079,8 +3082,11 @@ void SubprogramVisitor::Post(const parser::EntryStmt &stmt) {
30793082
dummy->name(), "Previous declaration of '%s'"_en_US);
30803083
}},
30813084
dummy->details());
3085+
} else if (inExecutionPart_) {
3086+
dummy = &MakeSymbol(*dummyName, ObjectEntityDetails{true});
3087+
ApplyImplicitRules(*dummy);
30823088
} else {
3083-
dummy = &MakeSymbol(*dummyName, EntityDetails(true));
3089+
dummy = &MakeSymbol(*dummyName, EntityDetails{true});
30843090
}
30853091
entryDetails.add_dummyArg(*dummy);
30863092
} else {
@@ -3096,20 +3102,11 @@ void SubprogramVisitor::Post(const parser::EntryStmt &stmt) {
30963102
Symbol::Flag subpFlag{
30973103
inFunction ? Symbol::Flag::Function : Symbol::Flag::Subroutine};
30983104
Scope &outer{inclusiveScope.parent()}; // global or module scope
3105+
if (outer.IsModule() && !attrs.test(Attr::PRIVATE)) {
3106+
attrs.set(Attr::PUBLIC);
3107+
}
30993108
if (Symbol * extant{FindSymbol(outer, name)}) {
3100-
if (extant->has<ProcEntityDetails>()) {
3101-
if (!extant->test(subpFlag)) {
3102-
Say2(name,
3103-
subpFlag == Symbol::Flag::Function
3104-
? "'%s' was previously called as a subroutine"_err_en_US
3105-
: "'%s' was previously called as a function"_err_en_US,
3106-
*extant, "Previous call of '%s'"_en_US);
3107-
}
3108-
if (extant->attrs().test(Attr::PRIVATE)) {
3109-
attrs.set(Attr::PRIVATE);
3110-
}
3111-
outer.erase(extant->name());
3112-
} else {
3109+
if (!HandlePreviousCalls(name, *extant, subpFlag)) {
31133110
if (outer.IsGlobal()) {
31143111
Say2(name, "'%s' is already defined as a global identifier"_err_en_US,
31153112
*extant, "Previous definition of '%s'"_en_US);
@@ -3119,14 +3116,8 @@ void SubprogramVisitor::Post(const parser::EntryStmt &stmt) {
31193116
return;
31203117
}
31213118
}
3122-
if (outer.IsModule() && !attrs.test(Attr::PRIVATE)) {
3123-
attrs.set(Attr::PUBLIC);
3124-
}
31253119
Symbol &entrySymbol{MakeSymbol(outer, name.source, attrs)};
31263120
entrySymbol.set_details(std::move(entryDetails));
3127-
if (outer.IsGlobal()) {
3128-
MakeExternal(entrySymbol);
3129-
}
31303121
SetBindNameOn(entrySymbol);
31313122
entrySymbol.set(subpFlag);
31323123
Resolve(name, entrySymbol);
@@ -3186,24 +3177,37 @@ bool SubprogramVisitor::BeginSubprogram(
31863177

31873178
void SubprogramVisitor::EndSubprogram() { PopScope(); }
31883179

3180+
bool SubprogramVisitor::HandlePreviousCalls(
3181+
const parser::Name &name, Symbol &symbol, Symbol::Flag subpFlag) {
3182+
if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}; proc &&
3183+
!proc->isDummy() &&
3184+
!symbol.attrs().HasAny(Attrs{Attr::INTRINSIC, Attr::POINTER})) {
3185+
// There's a symbol created for previous calls to this subprogram or
3186+
// ENTRY's name. We have to replace that symbol in situ to avoid the
3187+
// obligation to rewrite symbol pointers in the parse tree.
3188+
if (!symbol.test(subpFlag)) {
3189+
Say2(name,
3190+
subpFlag == Symbol::Flag::Function
3191+
? "'%s' was previously called as a subroutine"_err_en_US
3192+
: "'%s' was previously called as a function"_err_en_US,
3193+
symbol, "Previous call of '%s'"_en_US);
3194+
}
3195+
EntityDetails entity;
3196+
if (proc->type()) {
3197+
entity.set_type(*proc->type());
3198+
}
3199+
symbol.details() = std::move(entity);
3200+
return true;
3201+
} else {
3202+
return symbol.has<UnknownDetails>() || symbol.has<SubprogramNameDetails>();
3203+
}
3204+
}
3205+
31893206
void SubprogramVisitor::CheckExtantProc(
31903207
const parser::Name &name, Symbol::Flag subpFlag) {
31913208
if (auto *prev{FindSymbol(name)}) {
3192-
if (prev->attrs().test(Attr::EXTERNAL) && prev->has<ProcEntityDetails>()) {
3193-
// this subprogram was previously called, now being declared
3194-
if (!prev->test(subpFlag)) {
3195-
Say2(name,
3196-
subpFlag == Symbol::Flag::Function
3197-
? "'%s' was previously called as a subroutine"_err_en_US
3198-
: "'%s' was previously called as a function"_err_en_US,
3199-
*prev, "Previous call of '%s'"_en_US);
3200-
}
3201-
EraseSymbol(name);
3202-
} else if (const auto *details{prev->detailsIf<EntityDetails>()}) {
3203-
if (!details->isDummy()) {
3204-
Say2(name, "Procedure '%s' was previously declared"_err_en_US, *prev,
3205-
"Previous declaration of '%s'"_en_US);
3206-
}
3209+
if (!IsDummy(*prev) && !HandlePreviousCalls(name, *prev, subpFlag)) {
3210+
SayAlreadyDeclared(name, *prev);
32073211
}
32083212
}
32093213
}

flang/test/Semantics/resolve18.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ subroutine s5
9898
module m6
9999
real :: f6
100100
interface g6
101-
!ERROR: Procedure 'f6' was previously declared
101+
!ERROR: 'f6' is already declared in this scoping unit
102102
real function f6()
103103
end function f6
104104
end interface g6
@@ -107,7 +107,7 @@ end module m6
107107
module m7
108108
integer :: f7
109109
interface g7
110-
!ERROR: Procedure 'f7' was previously declared
110+
!ERROR: 'f7' is already declared in this scoping unit
111111
real function f7()
112112
end function f7
113113
end interface g7
@@ -116,7 +116,7 @@ end module m7
116116
module m8
117117
real :: f8
118118
interface g8
119-
!ERROR: Procedure 'f8' was previously declared
119+
!ERROR: 'f8' is already declared in this scoping unit
120120
subroutine f8()
121121
end subroutine f8
122122
end interface g8

0 commit comments

Comments
 (0)