Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions flang/include/flang/Semantics/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -770,5 +770,7 @@ std::string GetCommonBlockObjectName(const Symbol &, bool underscoring);
// Check for ambiguous USE associations
bool HadUseError(SemanticsContext &, SourceName at, const Symbol *);

bool AreSameModuleSymbol(const Symbol &, const Symbol &);

} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_TOOLS_H_
10 changes: 1 addition & 9 deletions flang/lib/Semantics/check-declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2976,14 +2976,6 @@ static std::optional<std::string> DefinesGlobalName(const Symbol &symbol) {
return std::nullopt;
}

static bool IsSameSymbolFromHermeticModule(
const Symbol &symbol, const Symbol &other) {
return symbol.name() == other.name() && symbol.owner().IsModule() &&
other.owner().IsModule() && symbol.owner() != other.owner() &&
symbol.owner().GetName() &&
symbol.owner().GetName() == other.owner().GetName();
}

// 19.2 p2
void CheckHelper::CheckGlobalName(const Symbol &symbol) {
if (auto global{DefinesGlobalName(symbol)}) {
Expand All @@ -3001,7 +2993,7 @@ void CheckHelper::CheckGlobalName(const Symbol &symbol) {
(!IsExternalProcedureDefinition(symbol) ||
!IsExternalProcedureDefinition(other))) {
// both are procedures/BLOCK DATA, not both definitions
} else if (IsSameSymbolFromHermeticModule(symbol, other)) {
} else if (AreSameModuleSymbol(symbol, other)) {
// Both symbols are the same thing.
} else if (symbol.has<ModuleDetails>()) {
Warn(common::LanguageFeature::BenignNameClash, symbol.name(),
Expand Down
78 changes: 50 additions & 28 deletions flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3963,40 +3963,43 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
}
}

auto AreSameModuleProcOrBothInterfaces{[](const Symbol &p1,
const Symbol &p2) {
if (IsProcedure(p1) && !IsPointer(p1) && IsProcedure(p2) &&
!IsPointer(p2)) {
auto classification{ClassifyProcedure(p1)};
if (classification == ClassifyProcedure(p2)) {
if (classification == ProcedureDefinitionClass::External) {
const auto *subp1{p1.detailsIf<SubprogramDetails>()};
const auto *subp2{p2.detailsIf<SubprogramDetails>()};
return subp1 && subp1->isInterface() && subp2 && subp2->isInterface();
} else if (classification == ProcedureDefinitionClass::Module) {
return AreSameModuleSymbol(p1, p2);
}
}
}
return false;
}};

auto AreSameProcedure{[&](const Symbol &p1, const Symbol &p2) {
if (&p1 == &p2) {
if (&p1.GetUltimate() == &p2.GetUltimate()) {
return true;
} else if (p1.name() != p2.name()) {
return false;
} else if (p1.attrs().test(Attr::INTRINSIC) ||
p2.attrs().test(Attr::INTRINSIC)) {
return p1.attrs().test(Attr::INTRINSIC) &&
p2.attrs().test(Attr::INTRINSIC);
} else if (!IsProcedure(p1) || !IsProcedure(p2)) {
return false;
} else if (IsPointer(p1) || IsPointer(p2)) {
return false;
} else if (const auto *subp{p1.detailsIf<SubprogramDetails>()};
subp && !subp->isInterface()) {
return false; // defined in module, not an external
} else if (const auto *subp{p2.detailsIf<SubprogramDetails>()};
subp && !subp->isInterface()) {
return false; // defined in module, not an external
} else if (AreSameModuleProcOrBothInterfaces(p1, p2)) {
// Both are external interfaces, perhaps to the same procedure,
// or both are module procedures from modules with the same name.
auto p1Chars{evaluate::characteristics::Procedure::Characterize(
p1, GetFoldingContext())};
auto p2Chars{evaluate::characteristics::Procedure::Characterize(
p2, GetFoldingContext())};
return p1Chars && p2Chars && *p1Chars == *p2Chars;
} else {
// Both are external interfaces, perhaps to the same procedure
auto class1{ClassifyProcedure(p1)};
auto class2{ClassifyProcedure(p2)};
if (class1 == ProcedureDefinitionClass::External &&
class2 == ProcedureDefinitionClass::External) {
auto chars1{evaluate::characteristics::Procedure::Characterize(
p1, GetFoldingContext())};
auto chars2{evaluate::characteristics::Procedure::Characterize(
p2, GetFoldingContext())};
// same procedure interface defined identically in two modules?
return chars1 && chars2 && *chars1 == *chars2;
} else {
return false;
}
return false;
}
}};

Expand Down Expand Up @@ -4097,13 +4100,32 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
localSymbol = &newSymbol;
}
if (useGeneric) {
// Combine two use-associated generics
// Combine two use-associated generics.
localSymbol->attrs() =
useSymbol.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE};
localSymbol->flags() = useSymbol.flags();
AddGenericUse(*localGeneric, localName, useUltimate);
localGeneric->clear_derivedType();
localGeneric->CopyFrom(*useGeneric);
// Don't duplicate specific procedures.
std::size_t originalLocalSpecifics{localGeneric->specificProcs().size()};
std::size_t useSpecifics{useGeneric->specificProcs().size()};
CHECK(originalLocalSpecifics == localGeneric->bindingNames().size());
CHECK(useSpecifics == useGeneric->bindingNames().size());
std::size_t j{0};
for (const Symbol &useSpecific : useGeneric->specificProcs()) {
SourceName useBindingName{useGeneric->bindingNames()[j++]};
bool isDuplicate{false};
std::size_t k{0};
for (const Symbol &localSpecific : localGeneric->specificProcs()) {
if (localGeneric->bindingNames()[k++] == useBindingName &&
AreSameProcedure(localSpecific, useSpecific)) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
localGeneric->AddSpecificProc(useSpecific, useBindingName);
}
}
}
localGeneric->clear_derivedType();
if (combinedDerivedType) {
Expand Down
5 changes: 5 additions & 0 deletions flang/lib/Semantics/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1870,4 +1870,9 @@ bool HadUseError(
}
}

bool AreSameModuleSymbol(const Symbol &symbol, const Symbol &other) {
return symbol.name() == other.name() && symbol.owner().IsModule() &&
other.owner().IsModule() && symbol.owner().GetName() &&
symbol.owner().GetName() == other.owner().GetName();
}
} // namespace Fortran::semantics
25 changes: 25 additions & 0 deletions flang/test/Semantics/modfile80.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
!RUN: %flang_fc1 -DPART1 %s
!RUN: %flang_fc1 -DPART2 -fhermetic-module-files %s
!RUN: %flang_fc1 -DPART3 | FileCheck --allow-empty %s
!CHECK-NOT: error:

#if defined PART1
module modfile80a
interface generic
module procedure specific
end interface
contains
subroutine specific
end
end
#elif defined PART2
module modfile80b
use modfile80a
end
#else
program test
use modfile80a
use modfile80b
call generic
end
#endif