Skip to content

Commit

Permalink
[flang] Silence bogus USE statement error (#79896)
Browse files Browse the repository at this point in the history
When there are multiple USE statement for a particular module using
renaming, it is necessary to collect a set of all of the original
renaming targets before processing any of USE statements that don't have
ONLY: clauses.

Currently, if there is a name in the module that can't be added to the
current scope -- due to a conflict with an internal or module
subprogram, or with a previously use-associated name -- the compiler
will emit a bogus error message even if that conflicting name appear on
a later USE statement of the same module as the target of a renaming.

The new regression test case added with this patch provides a motivating
example.
  • Loading branch information
klausler committed Jan 29, 2024
1 parent 0aff71c commit c322e92
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 31 deletions.
66 changes: 35 additions & 31 deletions flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,7 @@ class ModuleVisitor : public virtual ScopeHandler {
void ApplyDefaultAccess();
Symbol &AddGenericUse(GenericDetails &, const SourceName &, const Symbol &);
void AddAndCheckModuleUse(SourceName, bool isIntrinsic);
void CollectUseRenames(const parser::UseStmt &);
void ClearUseRenames() { useRenames_.clear(); }
void ClearUseOnly() { useOnly_.clear(); }
void ClearModuleUses() {
Expand All @@ -769,8 +770,8 @@ class ModuleVisitor : public virtual ScopeHandler {
std::optional<SourceName> prevAccessStmt_;
// The scope of the module during a UseStmt
Scope *useModuleScope_{nullptr};
// Names that have appeared in a rename clause of a USE statement
std::set<std::pair<SourceName, Scope *>> useRenames_;
// Names that have appeared in a rename clause of USE statements
std::set<std::pair<SourceName, SourceName>> useRenames_;
// Names that have appeared in an ONLY clause of a USE statement
std::set<std::pair<SourceName, Scope *>> useOnly_;
// Intrinsic and non-intrinsic (explicit or not) module names that
Expand All @@ -790,14 +791,14 @@ class ModuleVisitor : public virtual ScopeHandler {
void DoAddUse(
SourceName, SourceName, Symbol &localSymbol, const Symbol &useSymbol);
void AddUse(const GenericSpecInfo &);
// If appropriate, erase a previously USE-associated symbol
void EraseRenamedUse(const Symbol *);
// Record a name appearing as the target of a USE rename clause
void AddUseRename(const SourceName &name) {
useRenames_.emplace(std::make_pair(name, useModuleScope_));
void AddUseRename(SourceName name, SourceName moduleName) {
useRenames_.emplace(std::make_pair(name, moduleName));
}
bool IsUseRenamed(const SourceName &name) const {
return useRenames_.find({name, useModuleScope_}) != useRenames_.end();
return useModuleScope_ && useModuleScope_->symbol() &&
useRenames_.find({name, useModuleScope_->symbol()->name()}) !=
useRenames_.end();
}
// Record a name appearing in a USE ONLY clause
void AddUseOnly(const SourceName &name) {
Expand Down Expand Up @@ -2838,11 +2839,34 @@ bool ModuleVisitor::Pre(const parser::Only &x) {
return false;
}

void ModuleVisitor::CollectUseRenames(const parser::UseStmt &useStmt) {
auto doRename{[&](const parser::Rename &rename) {
if (const auto *names{std::get_if<parser::Rename::Names>(&rename.u)}) {
AddUseRename(std::get<1>(names->t).source, useStmt.moduleName.source);
}
}};
common::visit(
common::visitors{
[&](const std::list<parser::Rename> &renames) {
for (const auto &rename : renames) {
doRename(rename);
}
},
[&](const std::list<parser::Only> &onlys) {
for (const auto &only : onlys) {
if (const auto *rename{std::get_if<parser::Rename>(&only.u)}) {
doRename(*rename);
}
}
},
},
useStmt.u);
}

bool ModuleVisitor::Pre(const parser::Rename::Names &x) {
const auto &localName{std::get<0>(x.t)};
const auto &useName{std::get<1>(x.t)};
SymbolRename rename{AddUse(localName.source, useName.source)};
AddUseRename(useName.source);
Resolve(useName, rename.use);
Resolve(localName, rename.local);
return false;
Expand Down Expand Up @@ -2970,31 +2994,8 @@ static bool ConvertToUseError(
}
}

// If a symbol has previously been USE-associated and did not appear in
// an ONLY clause or renaming, erase it from the current scope. This is
// necessary when a name appears as the target of a later USE rename clause.
void ModuleVisitor::EraseRenamedUse(const Symbol *useSymbol) {
if (!useSymbol) {
return;
}
const SourceName &name{useSymbol->name()};
if (const Symbol * symbol{FindInScope(name)}) {
if (const auto *useDetails{symbol->detailsIf<UseDetails>()}) {
const Symbol &moduleSymbol{useDetails->symbol()};
if (moduleSymbol.name() == name &&
moduleSymbol.owner() == useSymbol->owner() && !IsUseOnly(name) &&
!IsUseRenamed(name)) {
EraseSymbol(*symbol);
}
}
}
}

void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
Symbol &originalLocal, const Symbol &useSymbol) {
if (localName != useSymbol.name()) {
EraseRenamedUse(&useSymbol);
}
Symbol *localSymbol{&originalLocal};
if (auto *details{localSymbol->detailsIf<UseErrorDetails>()}) {
details->add_occurrence(location, *useModuleScope_);
Expand Down Expand Up @@ -8073,6 +8074,9 @@ bool ResolveNamesVisitor::Pre(const parser::SpecificationPart &x) {
Walk(accDecls);
Walk(ompDecls);
Walk(compilerDirectives);
for (const auto &useStmt : useStmts) {
CollectUseRenames(useStmt.statement.value());
}
Walk(useStmts);
UseCUDABuiltinNames();
ClearUseRenames();
Expand Down
21 changes: 21 additions & 0 deletions flang/test/Semantics/resolve122.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
! RUN: %flang_fc1 -fsyntax-only -pedantic %s 2>&1 | FileCheck %s --allow-empty
! Regression test for bogus use-association name conflict
! error: Cannot use-associate 's2'; it is already declared in this scope
! CHECK-NOT: error:
module m1
contains
subroutine s1
end
subroutine s2
end
end

module m2
use m1, s1a => s1
use m1, s2a => s2
contains
subroutine s1
end
subroutine s2
end
end

0 comments on commit c322e92

Please sign in to comment.